Main Analysis
After analyzing the quality of the data set, we got rid of data in which the Borough is missing and the year is before 2013.
ViolationsData <- ViolationsData %>% filter (BORO != "Missing")
ViolationsData <- ViolationsData %>% filter(
as.numeric(format(INSPECTION.DATE , '%Y')) > 2012)
Now we can get a better picture of the total number of inspections by year and borough.
boroughPlot <- ggplot(ViolationsData, aes(BORO,fill=BORO))
boroughPlot + geom_bar() + theme(legend.position="none") +
facet_wrap(~factor(as.numeric( format(INSPECTION.DATE , '%Y')))) +
ggtitle("Total Inspections from 2013-2017 in each Borough") +
xlab("Borough") + ylab("Number of Inspections") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

After 2013, there seems to be a consistent amount of inspections acros the years. The number of inspections by borough also seems to make sense since we expect Manhattan to have the largest number of restuarants.
Next, we took a look at the grade distribution by borough.
inspection_grades <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE, -PHONE, -ACTION, -VIOLATION.CODE, -VIOLATION.DESCRIPTION, -CRITICAL.FLAG, -SCORE, -GRADE.DATE, -RECORD.DATE, -INSPECTION.TYPE,-CUISINE.DESCRIPTION)
inspection_grades_woyear<-inspection_grades %>% select(-INSPECTION.DATE)
inspection_grades_woyear <- inspection_grades_woyear %>% gather(key, value, -BORO) %>% group_by(BORO, key, value) %>% tally %>% spread(value, n, fill = 0)
names(inspection_grades_woyear)[names(inspection_grades_woyear)=="key"] <- "grade"
names(inspection_grades_woyear)[names(inspection_grades_woyear)==""] <- "`Unknown"
inspection_grades_woyear <- inspection_grades_woyear %>% gather(key, value, -BORO,-grade)
RelFreq<-function(m){
((m )/sum(m))
}
inspection_grades_woyear<-inspection_grades_woyear %>% group_by(BORO,grade) %>%
mutate(percentage = (value/sum(value))*100)
ggplot(inspection_grades_woyear, aes(BORO, percentage ,fill= key)) +
geom_bar(stat="identity", position = "dodge") +
ggtitle('%Grade distribution across boroughs') +
labs(x = "Borough", y ="Percentage") + guides(fill=guide_legend(title="Grade"))

We initially hypothesized that we would see a pattern in grade distribution by borough, however, the plot shows us that grade distributions are almost the same regardless of borough.
inspection_grades_year<-inspection_grades%>% mutate(year=factor(as.numeric(format(INSPECTION.DATE , '%Y'))))
inspection_grades_year<-inspection_grades_year%>% select(-INSPECTION.DATE)
inspection_grades_year <- inspection_grades_year %>% gather(key, value, -BORO,-year) %>% group_by(BORO,year, key, value) %>%
tally %>% spread(value, n, fill = 0)# %>% gather(blah, -BORO, -key) #summarize(aprop = A/(A+B+C+))
names(inspection_grades_year)[names(inspection_grades_year)=="key"] <- "grade"
names(inspection_grades_year)[names(inspection_grades_year)==""] <- "`Unknown"
inspection_grades_year <- inspection_grades_year %>% gather(key, value, -BORO,-grade,-year)
RelFreq<-function(m){
((m )/sum(m))
}
inspection_grades_year<-inspection_grades_year %>% group_by(BORO,grade,year) %>%
mutate(percentage = (value/sum(value))*100)
ggplot(inspection_grades_year, aes(BORO, percentage ,fill= key)) +
geom_bar(stat="identity", position = "dodge") +facet_wrap(~year,nrow=2,ncol=3)+
guides(fill=guide_legend(title="Grade"))+
ggtitle("%Grade distribution by BOROUGH")

Adding year to this analysis showed us an increase in the proportian of As in Sataten Island in 2015 but seemed consistent throughout the rest of the plot.
We decided that borough may be too general and thus looked at grade distribution by zip code across the various years. We used a heat map to do so.
library(viridis)
nonYearDataForHeatMap<-ViolationsData %>% select(GRADE,ZIPCODE)
nonYearDataForHeatMap <- nonYearDataForHeatMap %>% group_by(GRADE,ZIPCODE) %>% tally
RelFreq<-function(m){
((m )/sum(m))
}
nonYearDataForHeatMap<- nonYearDataForHeatMap %>% group_by(ZIPCODE)%>%
mutate(percentage = (n/sum(n))*100)
ggplot(nonYearDataForHeatMap, aes(GRADE,
ZIPCODE, fill = percentage)) +
geom_tile() +
scale_fill_viridis() +
ggtitle("Percentage grade distribution by zipcode\n ")+ylab("Zip Code") + theme(plot.title = element_text(size = 35, face = "bold"),
axis.text.x = element_text(colour="grey20",size=15,angle=0,hjust=.5,
vjust=.5,face="plain"),
axis.text.y = element_text(colour="grey20",size=10,angle=0,hjust=1,
vjust=0,face="plain"),
axis.title.x = element_text(colour="grey20",size=25,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=30,angle=90,hjust=.5,
vjust=.5,face="plain"),
legend.title = element_text(size=20),
legend.text=element_text(size=20), legend.key.size = unit(1, 'in'))

It is interesting to note that missing grades are probably the most probable in general. There are some zip codes with almost no missing grades. The restuarants in those same zip codes seem to mostly have all A grades. Another interesting point is 1 zip code which has all Not Yet Graded grades. In geneeral missing gradees and grades of an A seem the most common. This is followed by grades of a B.
The next part of our analysis was to look at the average scores of each cuisine. With this information, we can help consumers see what kinds of establishments have the best and worst scores on average. This in term can help a consumer choose a type of cuisine when they are hungry.
average_scores <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -INSPECTION.DATE, -ACTION,
-VIOLATION.CODE, -VIOLATION.DESCRIPTION,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE)
average_cuisine <- average_scores %>% group_by(CUISINE.DESCRIPTION) %>% na.omit %>%
dplyr::summarize(average_score = mean(SCORE))
average_cuisine <- arrange(average_cuisine, -average_score)
ggplot(average_cuisine, aes(reorder(x = CUISINE.DESCRIPTION, --average_score), average_score,fill="Blue")) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average Scores Across Cuisines")+xlab("Cuisine Description")+ylab("Average Score")+geom_text(aes(label = sprintf("%.2f", average_score)),position=position_stack(vjust=0.5),vjust = 0.5, size = 3) + theme(plot.title = element_text(size = 25, face = "bold"),
axis.title.x = element_text(colour="grey20",size=20,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=20,angle=90,hjust=.5,
vjust=.5,face="plain"))

worst10 <- average_cuisine[1:10,]
ggplot(worst10, aes(reorder(x = CUISINE.DESCRIPTION, --average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average score of Worst 10 cuisines")+xlab("Cuisine description")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position=position_stack(vjust=0.5))

n <- nrow(average_cuisine)
best10 <- average_cuisine[(n- 10):n,]
best10 <- best10[order(best10$average_score),]
ggplot(best10, aes(reorder(x = CUISINE.DESCRIPTION, -average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average score of top 10 cuisines")+xlab("Cuisine description")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position = position_dodge(width = 1),#position=position_stack(vjust=0.5)
vjust = 0.5, size = 4)

It is interesting that the mysterious “not applicable”" cuisine is one of the best!
In this next plot, we wanted to see if the average score significantly differed by Borough
average_borough <- average_scores %>% group_by(BORO) %>% na.omit %>%
dplyr::summarize(average_score = mean(SCORE))
ggplot(average_borough, aes(reorder(x = BORO, --average_score), average_score, fill = BORO)) + geom_bar(stat='identity') + theme(legend.position = 'none')+ggtitle("Average score across boroughs")+xlab("Borough")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position = position_dodge(width = 1),
vjust = -0.5, size = 3)

Although we see slight difference, the boroughs have approximately the same average score. Staten Island may be the one exception. We also faceted by year to see if that made a difference, but the results were essentially the same as in the plot above.
So far we looked at grades and scores but not the actual violations. Whare are the top violations restaurants usually face?
violations<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -INSPECTION.DATE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE)
vs <- violations %>% group_by(VIOLATION.DESCRIPTION) %>% na.omit %>%
dplyr::summarize(count = n())
vs <- arrange(vs, -count)
topviolations <- vs[1:10,]
library(stringr)
topviolations$viol = str_wrap(topviolations$VIOLATION.DESCRIPTION, width = 15)
ggplot(topviolations, aes(reorder(viol, -count), count,fill=viol)) + geom_bar(stat='identity') +
theme(legend.position = 'none')+ggtitle("Top 10 violations \n")+xlab("Violation description")+ylab("count")+geom_text(aes(label = sprintf("%.0f", count)),
position = position_dodge(width = 1), vjust = -0.5, size = 7) + theme(plot.title = element_text(size = 40, face = "bold"),
axis.text.x = element_text(colour="grey20",size=20,angle=0,hjust=.5,
vjust=.5,face="plain"),
axis.text.y = element_text(colour="grey20",size=30,angle=0,hjust=1,
vjust=0,face="plain"),
axis.title.x = element_text(colour="grey20",size=30,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=30,angle=90,hjust=.5,
vjust=.5,face="plain"))

We also hypothesized that the type of inspections would generally vary by Borough but even this was mostly consistent.
library(viridis)
mos<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -SCORE, -CUISINE.DESCRIPTION, -VIOLATION.DESCRIPTION)
mos$year <- factor(as.numeric( format(mos$INSPECTION.DATE , '%Y')))
mos <- mos %>% select(-INSPECTION.DATE)
average_mos <- mos %>% group_by(BORO, year, INSPECTION.TYPE) %>% tally %>%
group_by(BORO, year) %>%
mutate(percentage = n / sum(n))
#average_cuisine <- arrange(average_cuisine, -average_score)
library(vcd)
average_mos <- average_mos %>% select(-n)
ggplot(average_mos, aes(BORO,
INSPECTION.TYPE, fill = percentage)) +
geom_tile() +
scale_fill_viridis() +
#facet_wrap(~BORO)
ggtitle("AVERAGE VIOLATION SCORE BY ZIP CODE\n ")+
theme(plot.title = element_text(size = 30, face = "bold"),
axis.text.x = element_text(colour="grey20",size=20,angle=0,hjust=.5,
vjust=.5,face="plain"),
axis.text.y = element_text(colour="grey20",size=15,angle=0,hjust=1,
vjust=0,face="plain"),
axis.title.x = element_text(colour="grey20",size=25,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=25,angle=90,hjust=.5,
vjust=.5,face="plain"),
legend.title = element_text(size=30),
legend.text=element_text(size=20), legend.key.size = unit(1, 'in'))

One thing we noticed was that Staten island has the least Cycle Inspection/Initial Inspection. Maybe they were opening up the least new restuarants. They also had the most cycle inspection/re-inspection percentage. As we’ll see in the maps below, those reinspections may have helped restaurants in staten island improve their grades and scores.
One factor of our data set we haven’t discussed too much is the Critical flag, saying whether or not a violation is critical. Once again, we assumed that over the years and across different boroughs, there would be some pattern in critical violations. As can be inferred from the following plot, there is not.
CriticalityData<- ViolationsData %>% select(BORO,INSPECTION.DATE,CRITICAL.FLAG) %>% na.omit()
CriticalityData$year<-factor(as.numeric( format(CriticalityData$INSPECTION.DATE , '%Y')))
#CriticalityData <- CriticalityData %>%select(-INSPECTION.DATE)
CriticalityData <- CriticalityData %>%select(-INSPECTION.DATE) %>% gather(key, value, -BORO, -year) %>% group_by(BORO, year,key,value) %>% tally %>% spread(value, n, fill = 0)
names(CriticalityData)[5] <- "NotApplicable"
names(CriticalityData)[6] <- "NonCritical"
CriticalityDataPercentage<-CriticalityData %>% summarize(criticalPercent = Critical/(Critical+NotApplicable+NonCritical), NotApplicablePercent = NotApplicable/(Critical+NotApplicable+NonCritical), NonCriticalPercent = NonCritical/(Critical+NotApplicable+NonCritical))#
names(CriticalityDataPercentage)[4] <- "Critical"
names(CriticalityDataPercentage)[5] <- "NotApplicable"
names(CriticalityDataPercentage)[6] <- "NonCritical"
CriticalityDataPercentage<-CriticalityDataPercentage%>% gather(key1, value, -BORO, -year,-key)
ggplot(CriticalityDataPercentage, aes(BORO, value, fill = key1)) +
geom_bar(stat="identity", position = "dodge") +
scale_fill_brewer(palette = "Set1")+ xlab("BOROUGH")+ylab("CRITICALITY PERCENTAGES") +theme(axis.text.x = element_text(angle = 45, hjust = 1))+ ggtitle("Grouped barchart of grade frequency in each cuisine category \n when there was a violation reported")+facet_wrap(~year,nrow=2,ncol=3)+guides(fill=guide_legend(title="Criticality \n category"))

We attempted to further analyze the critical flag but we learned that the critical flag did not have too much impact on grade or scores. There was a lot of data with a grade of A but a Critical flag while others with a very high score by no critical flag.
VISUALISING DATA WITH MAPS
For the remainder of the analysis, we will be working with Tableau. We chose Tableau because we wanted to plot elegent maps. Tableau provides a simpler and more elegent way to do so than in R.
- Please note that there is a tutorial for deriving maps from generated datset in Tableau in the github repository as ChoroplethMaps.html under the “FinalReport” folder in the Github Repository. It was created by our very own Lakshya Garg.
The code chunks will generate the data that we upload to Tableau. In the following analysis, we explore the proportion of A grades based on neighborhood over the years.
#####GENERATE GRADE PROPOERTION DATASET BY YEAR FOR TABLEAU PLOTTING
zipdata<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET,
-PHONE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -SCORE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE, -VIOLATION.DESCRIPTION, -CUISINE.DESCRIPTION, -BORO) %>% na.omit()
zipdata$year<-factor(as.numeric( format(zipdata$INSPECTION.DATE , '%Y')))
zipdataGradePercentage <- zipdata %>%select(-INSPECTION.DATE) %>%gather(key, value, -ZIPCODE, -year) %>% group_by(ZIPCODE, year, key, value) %>%
tally %>% spread(value, n, fill = 0) %>% summarize(aprop = A/(A+B+C), bprop = B/(A+B+C), cprop = C/(A+B+C) )
# ggplot(zipdataGradePercentage, aes(reorder(x = ZIPCODE, --aprop), aprop)) + geom_bar(stat='identity') +
# coord_flip() + facet_wrap(~year)
# theme( axis.text = element_text(size = 3))
PROPORTIONS OF GRADE A ACROSS YEARS
Over the years, the proportion of A’s has increased, as represented by the darker red shading of the map. It is too early to study 2017 in depth due to the limited number of inspections so far. Note that 2017 data maps are only for quater1 and are likely to change.
knitr::include_graphics('Aprop2013.png')

knitr::include_graphics('Aprop2014.png')

knitr::include_graphics('Aprop2015.png')

knitr::include_graphics('Aprop2016.png')

knitr::include_graphics('Aprop2017.png')

PROPORTIONS OF GRADE B ACROSS YEARS
Let’s look at how the proportion of B’s change.We can see that over the years, there seem to be less B’s which makes sense since over the years we have more grades of A. Note that 2017 data maps are only for quater1 and are likely to change.
knitr::include_graphics('Bprop1.png')

knitr::include_graphics('Bprop2.png')

knitr::include_graphics('Bprop3.png')

knitr::include_graphics('Bprop4.png')

knitr::include_graphics('Bprop5.png')

AVERAGE SCORES BY ZIPCODE OVER YEARS
Let’s look at the average scores by neighborhood. We have already done so by cuisine. Over the years, we have a lower Average Score. These NYC inspections must be prompting resturants to improve their facilities and follow regulations!
Note that 2017 data maps are only for quater1 and are likely to change.
knitr::include_graphics('AvgScore2013.png')

knitr::include_graphics('AvgScore2014.png')

knitr::include_graphics('AvgScore2015.png')

knitr::include_graphics('AvgScore2016.png')

knitr::include_graphics('AvgScore2017.png')

AVERAGE RE-INSPECTIONS OVER YEARS
We decided to see which areas had the highest average number of reinspections. Maybe this can explain the better scores and grades over time.Interestingly enough, the areas with the most reinspections seem to be the ones in which the grades and scores improved. The system of reinspections must be working!
Note that 2017 data maps are only for quater1 and are likely to change.
### DATA GENERATION
library(stringr)
reinspect <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -CUISINE.DESCRIPTION, -BORO, -SCORE,
-PHONE, INSPECTION.DATE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE)
reinspect$year<-factor(as.numeric( format(reinspect$INSPECTION.DATE , '%Y')))
#inspection_types <- INSPECTION.TYPE
reinspect <- reinspect %>%select(-INSPECTION.DATE) %>% na.omit %>% filter(str_detect(INSPECTION.TYPE, "Re-inspection"))%>%group_by(VIOLATION.DESCRIPTION, year, ZIPCODE ) %>% tally# summarise(re = sum(str_count(reinspect$INSPECTION.TYPE, "Re-inspection")))
knitr::include_graphics('AvgReinspect2013.png')

knitr::include_graphics('AvgReinspect2014.png')

knitr::include_graphics('AvgReinspect2015.png')

knitr::include_graphics('AvgReinspect2016.png')

knitr::include_graphics('AvgReinspect2017.png')

LS0tCnRpdGxlOiAiVG8gRWF0IE9yIE5vdCBUbyBFYXQ/IgphdXRob3I6ICJKb25hdGhhbiBHYWxzdXJrYXIgLSBqZmcyMTUwIHwgTGFrc2h5YSBHYXJnIC0gbGcyOTA2IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCiMjIEludHJvZHVjdGlvbgoKSW4gb25lIG9mIHRoZSBncmVhdGVzdCBjaXRpZXMgaW4gdGhlIHdvcmxkLCBOWUMsIHdlIGhhdmUgYW4gYWJ1bmRhbnQgYW1vdW50IG9mIG9wdGlvbnMgdG8gY2hvb3NlIGZyb20gd2hlbiBpdCBjb21lcyB0byB3aGVyZSB3ZSBlYXQsIHdoZXRoZXIgd2UgYXJlIGxvb2tpbmcgZm9yIGZpbmUgZGluaW5nLCBmYXN0IGZvb2QsIG9yIHNvbWV0aGluZyBpbiBiZXR3ZWVuLiBUaGUgY3Vpc2luZSBjaG9pY2VzIHNlZW0ganVzdCBhcyBlbmRsZXNzLiBJcyB0aGVyZSBhIGdvb2Qgd2F5IHRvIGhlbHAgY2hvb3NlIGEgcmVzdGF1cmFudCB0byBlYXQgaW4gb3IgYSBnZW5lcmFsIGxvY2F0aW9uPyBBbHRob3VnaCBub3QgYW4gZWFzeSB0YXNrLCBvbmUgdGhpbmcgd2UgY2FuIGFsbCBhZ3JlZSBvbiBpcyB0aGF0IG5vYm9keSB3YW50cyB0byBlYXQgaW4gYSByZXN0YXVyYW50IHJpZGRlbiB3aXRoIGhlYWx0aCB2aW9sYXRpb25zLiBJbiBvdXIgcHJvamVjdCwgd2Ugd2lsbCBleHBsb3JlIGFuZCBhbmFseXplIE5ZQ+KAmXMgcmVzdGF1cmFudCBpbnNwZWN0aW9uIHJlc3VsdHMgZnJvbSAyMDEzLTIwMTcgb2YgdGhlIGZpdmUgYm9yb3VnaHMuCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBhbnN3ZXJpbmc6CgoxLiBXaGljaCBjdWlzaW5lcyBoYXZlIHRoZSBsZWFzdCBhbmQgbW9zdCB2aW9sYXRpb25zIGFsb25nIHdpdGggdGhlaXIgYXNzb2NpYXRlZCBzY29yZT8KCjIuIFdoYXQgcGFydHMgb2YgTllDIGhhdmUgdGhlIGxlYXN0IGFuZCBtb3N0IHZpb2xhdGlvbnM/CgozLiBXZSBoeXBvdGhlc2l6ZSB0aGF0IGxvY2F0aW9uIGlzIGhpZ2hseSBhc3NvY2lhdGVkIHdpdGggaW5zcGVjdGlvbiBncmFkZSBhbmQgc28gd2Ugd2lsbCBiZSBzZWFyY2hpbmcgZm9yIHBhdHRlcm5zIGJldHdlZW4gdGhlc2UgdmFyaWFibGVzLgoKNC4gV2UgYXJlIGFsc28gaW50ZXJlc3RlZCBpbiBzZWVpbmcgaG93IGluc3BlY3Rpb24gZ3JhZGUgYW5kIHNjb3JlIGNoYW5nZXMgb3ZlciB0aW1lICh5ZWFycykgYmFzZWQgdXBvbiBjdWlzaW5lIGFuZCBsb2NhdGlvbi4KCjUuIEEgZGVzY3JpcHRpb24gb2YgdmlvbGF0aW9ucyBpcyBhbHNvIHByb3ZpZGVkIGluIHRoZSBkYXRhIGFuZCB3ZSB3b3VsZCBsaWtlIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBjb21tb24gY2F1c2VzIG9mIHRob3NlIHZpb2xhdGlvbnMgYmFzZWQgdXBvbiB0aGUgZGVzY3JpcHRpb24uCgo2LiBJcyB0aGVyZSBhIHBhdHRlcm4vdHJlbmQgaW4gdmlvbGF0aW9ucy9pbnNwZWN0aW9uIHNjb3JlL2dyYWRlIGJhc2VkIHVwb24gcmVzdGF1cmFudCBjaGFpbnM/CgpXZSBmb3VuZCB0aGlzIGRhdGEgc2V0IGJ5IGV4cGxvcmluZyBOWUMgb3BlbiBkYXRhIHNldHMuIE91ciBsb3ZlIGZvciBmb29kIGFuZCBoZWFsdGggbWFkZSB0aGlzIGEgZ3JlYXQgb3B0aW9uLiBPbmUgb2Ygb3VyIHRlYW0gbWVtYmVycyB3aG8gcmVjZW50bHkgbW92ZWQgdG8gTllDIGlzIGhpZ2hseSBzZWxlY3RpdmUgYWJvdXQgdGhlIGZvb2Qgc2hlIGVhdHMgZHVlIHRvIGhlciByYXJlIGhlYWx0aCBjb25kaXRpb24gYW5kIGhlbmNlLCBoYXZpbmcgdGhlIGtpbmRzIG9mIHF1ZXN0aW9ucyBtZW50aW9uZWQgYWJvdmUgYW5zd2VyZWQgY2FuIHByb3ZlIHRvIGJlIGEgZ3JlYXQgYXNzZXQgdG8gYm90aCBoZXIgYW5kIG90aGVycyBzdWZmZXJpbmcgZnJvbSBoZWFsdGggY29uZGl0aW9ucyBvciB3aG8gbWF5IGp1c3QgYmUgcGlja3kgZWF0ZXJzISBUaGUgZGF0YSBjYW4gYmUgZm91bmQgYW5kIGRvd25sb2FkZWQgaGVyZTogaHR0cHM6Ly9kYXRhLmNpdHlvZm5ld3lvcmsudXMvSGVhbHRoL0RPSE1ILU5ldy1Zb3JrLUNpdHktUmVzdGF1cmFudC1JbnNwZWN0aW9uLVJlc3VsdHMveHg2Ny1rdDU5CgpUbyBkb3dubG9hZCwgY2xpY2sgdGhlIGV4cG9ydCBidXR0b24gb24gdGhlIHJpZ2h0IC0+IERvd25sb2FkIGFzIC0+IGNob29zZSB5b3VyIGZvcm1hdC4gRm9yIHRoaXMgYXNzaWduZW1lbnQgd2UgdXNlZCB0aGUgQ1NWIGZvcm1hdC4KCiMjIFRlYW0KCiMjIyMjIFRlYW0gTWVtYmVyczoKKyBKb25hdGhhbiBHYWxzdXJrYXIKKyBMYWtzaHlhIEdhcmcKCiMjIyMjIFRhc2sgRGlzdHJpYnV0aW9uCkdldCB0YWJsZSBmb3JtYXQgZm9yIHRoaXMKYGBge3J9CmxpYnJhcnkoa25pdHIpClRhc2tEaXN0cmlidXRpb24gPC0gcmVhZC5jc3YoZmlsZT0iVGFza0Rpc3RyaWJ1dGlvbi5jc3YiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsIHNlcD0iLCIsYXMuaXM9VFJVRSkKa2FibGUoVGFza0Rpc3RyaWJ1dGlvbiApCmBgYAoKIyMgQW5hbHlzaXMgb2YgRGF0YSBRdWFsaXR5ClRvIGJlZ2luIG91ciBhbmFseXNpcyBvZiBkYXRhIHF1YWxpdHksIGxldCdzIGxvYWQgb3VyIGRhdGEuCmBgYHtyfQpWaW9sYXRpb25zRGF0YSA8LSByZWFkLmNzdihmaWxlPSJpbnNwZWN0aW9uLmNzdiIsIGhlYWRlcj1UUlVFLCBzZXA9IiwiLCBhcy5pcz1UUlVFKQpgYGAKCiMjIyBEYXRhc2V0IERlc2NyaXB0aW9uCmBgYHtyfQpEYXRhc2V0RGVzY3JpcHRpb24gPC0gcmVhZC5jc3YoZmlsZT0iRGVzY3JpcHRpb25EYXRhc2V0LmNzdiIsIGhlYWRlcj1UUlVFLCBzZXA9IiwiLCBhcy5pcz1UUlVFKQprYWJsZShEYXRhc2V0RGVzY3JpcHRpb24gKQpgYGAKCkluIG9yZGVyIHRvIG1vcmUgZWFzaWx5IHdvcmsgd2l0aCBvdXIgZGF0YSBsZXQncyBlbnN1cmUgdGhhdCBldmVyeSBkYXRlIGlzIGluIGEgZGF0ZSBmb3JtYXQgcmF0aGVyIHRoYW4gYSBzdHJpbmcgYW5kIGV2ZXJ5IHN0cmluZyBpcyBhIGZhY3RvciB2YXJpYWJsZS4KYGBge3IgbWVzc2FnZT1GQUxTRX0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCiMjRGF0ZSBjb252ZXJzaW9uClZpb2xhdGlvbnNEYXRhIDwtIFZpb2xhdGlvbnNEYXRhICU+JQogIG11dGF0ZShJTlNQRUNUSU9OLkRBVEU9IGFzLkRhdGUoSU5TUEVDVElPTi5EQVRFLCBmb3JtYXQ9ICIlbS8lZC8lWSIpKSU+JQogIG11dGF0ZShHUkFERS5EQVRFPSBhcy5EYXRlKEdSQURFLkRBVEUsIGZvcm1hdD0gIiVtLyVkLyVZIikpJT4lCiAgbXV0YXRlKFJFQ09SRC5EQVRFPSBhcy5EYXRlKFJFQ09SRC5EQVRFLCBmb3JtYXQ9ICIlbS8lZC8lWSIpKQojI0ZhY3RvciBjb252ZXJzaW9uClZpb2xhdGlvbnNEYXRhIDwtIFZpb2xhdGlvbnNEYXRhICU+JQogIG11dGF0ZShDVUlTSU5FLkRFU0NSSVBUSU9OPSBhcy5mYWN0b3IoQ1VJU0lORS5ERVNDUklQVElPTikpJT4lCiAgbXV0YXRlKEJPUk89IGFzLmZhY3RvcihCT1JPKSklPiUKICBtdXRhdGUoVklPTEFUSU9OLkNPREU9IGFzLmZhY3RvcihWSU9MQVRJT04uQ09ERSkpJT4lCiAgbXV0YXRlKENSSVRJQ0FMLkZMQUc9IGFzLmZhY3RvcihDUklUSUNBTC5GTEFHKSklPiUKICBtdXRhdGUoR1JBREU9IGFzLmZhY3RvcihHUkFERSkpJT4lCiAgbXV0YXRlKElOU1BFQ1RJT04uVFlQRT0gYXMuZmFjdG9yKElOU1BFQ1RJT04uVFlQRSkpCgpzdW1tYXJpemUgPC0gZHBseXI6OnN1bW1hcml6ZQptdXRhdGUgPC0gZHBseXI6Om11dGF0ZQpgYGAKCgpNYW55IG9mIHRoZSBxdWVzdGlvbnMgd2UgYXJlIGludGVyZXN0ZWQgaW4gYW5zd2VyaW5nIGludm9sdmUgdHJlbmRzIGFjcm9zcyByZXN0dWFyYW50IGxvY2F0aW9ucy4gV2UgZmlyc3QgY2hlY2tlZCB0byBzZWUgdGhlIG51bWJlciBvZiByZXN0dWFyYW50IGluc3BlY3Rpb25zIGJ5IGJvcm91Z2guIEZyb20gdGhlIHBsb3QgYmVsb3csIHdlIG5vdGljZWQgdGhhdCB0aGVyZSB3ZXJlIGEgbnVtYmVyIG9mIGluc3BlY3Rpb25zIGluIHdoaWNoIHRoZSBCb3JvdWdoIGluZm9ybWF0aW9uIHdhcyBtaXNzaW5nIGFuZCB3b24ndCBoZWxwIG91ciBhbmFseXNpcy4KYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKYm9yb3VnaFBsb3QgPC0gZ2dwbG90KFZpb2xhdGlvbnNEYXRhLCBhZXMoQk9STywgZmlsbD1CT1JPKSkKYm9yb3VnaFBsb3QgKyBnZW9tX2JhcigpKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgZ2d0aXRsZSgnSW5zcGVjdGlvbiBDb3VudCBieSBCb3JvdWdoJykgKyAKICBsYWJzKHggPSAiQm9yb3VnaCIsIHkgPSJOdW1iZXIgb2YgSW5zcGVjdGlvbnMiKQpgYGAKCkFub3RoZXIgbWFpbiBmZWF0dXJlIG9mIG91ciBkYXRhIHNldCBpcyB0aGUgaW5zcGVjdGlvbiB5ZWFyIHNpbmNlIHdlIHdpc2ggdG8gZXhwbG9yZSBwYXR0ZXJzIGluIGluc3BlY3Rpb24gZ3JhZGVzL3Njb3JlcyBvdmVyIHRoZSB5ZWFycy4gRnJvbSB0aGUgcGxvdCBiZWxvdywgd2Ugbm90aWNlZCB0aGF0IHRoZXJlIGlzIGFsbW9zdCBubyBpbnNwZWN0aW9uIGRhdGEgYmVmb3JlIDIwMTMgYW5kIHN1cnByaXNpbmdseSBtb3JlIGluc3BlY3Rpb24gZGF0YSBpbiAxOTAwIHRoYW4gMjAxMiBhbmQgMjAxMS4gV2UgZGVjaWRlZCB0byBvbmx5IHdvcmsgd2l0aCBkYXRhIGZyb20gMjAxMyBhbmQgdXAuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIG51bWJlciBvZiBpbnNwZWN0aW9ucyBmb3IgMjAxNyBpcyBsb3cgc2luY2UgdGhlIDIwMTcgZGF0YSBpcyBvbmx5IGF2YWlsYWJsZSBmcm9tIEphbnVhcnkgLSBNYXJjaC4KYGBge3J9CnZpb2xhdGlvblllYXJzUGxvdCA8LSBnZ3Bsb3QoVmlvbGF0aW9uc0RhdGEsIGFlcyhmYWN0b3IoYXMubnVtZXJpYyhmb3JtYXQoSU5TUEVDVElPTi5EQVRFLCAnJVknKSkpLCBmaWxsPSJSZWQiKSkKdmlvbGF0aW9uWWVhcnNQbG90ICsgZ2VvbV9iYXIoKStjb29yZF9mbGlwKCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICt4bGFiKCJJbnNwZWN0aW9uIFllYXIiKSt5bGFiKCJJbnNwZWN0aW9uIENvdW50cyIpICsgZ2d0aXRsZSgiSW5zcGVjdGlvbiBDb3VudCBieSBZZWFyIikKYGBgCgpBbm90aGVyIGNydWNpYWwgZmVhdHVyZSBvZiBvdXIgZGF0YSBzZXQgaXMgZ3JhZGUgYSByZXN0YXVyYW50IHJlY2VpdmVkIGFmdGVyIGluc3BlY3Rpb24uIFdlIGRlY2lkZWQgdG8gcGxvdCBhIHN0YWNrZWQgYmFyIGNoYXJ0IGZvciB0byBzZWUgdGhlIGNvdW50IG9mIGVhY2ggdHlwZSBvZiBncmFkZSBmb3IgZXZlcnkgY3Vpc2luZS4gV2UgdXNlZCBhIHN0YWNrZWQgYmFyIGNoYXJ0IGJlY2F1c2Ugd2Ugd2FudGVkIHRvIHF1aWNrbHkgYXNzZXNzIHRoZSBtYWduaXR1ZGUgbWlzc2luZyB3aXRob3V0IHRha2luZyB1cCBleHRyYSByb29tLiBGcm9tIHRoZSBwbG90IGJlbG93LCBpdCB3YXMgc2hvY2tpbmcgdG8gc2VlIHRoYXQgd2UgZ2VuZXJhbGx5IGhhZCBtb3JlIG1pc3NpbmcgZ3JhZGVzIHRoYW4gZ3JhZGVzLiBUaGlzIHdhcyB0cnVlIHJlZ2FyZGxzcyBvZiBjdWlzaW5lLiBJdCB3YXMgYWxzbyBpbnRlcmVzdGluZyB0aGF0IHRoZSBncmFkZXMgd2VyZSBwdXJlbHkgbWlzc2luZyBhbmQgbm90IGNhdGVnb3JpemVkIGFzICJOb3QgWWV0IEdyYWRlZCIuCmBgYHtyLGZpZy5oZWlnaHQ9MTd9CmdncGxvdChWaW9sYXRpb25zRGF0YSwgYWVzKENVSVNJTkUuREVTQ1JJUFRJT04sIGZpbGwgPSBHUkFERSkpICsgZ2VvbV9iYXIoKSArIAogIGNvb3JkX2ZsaXAoKSArIGdndGl0bGUoIlN0YWNrZWQgQmFyIENoYXJ0IG9mIEdyYWRlIERpc3RyaWJ1dGlvbnMgQWNyb3NzIEN1aXNpbmVzIikgKwogIHhsYWIoJ0N1aXNpbmUnKSArIHlsYWIoJ0NvdW50JykgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcwLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NjAsYW5nbGU9MCxoanVzdD0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MzAsYW5nbGU9MCxoanVzdD0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwgIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT02MCxhbmdsZT0wLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUwLGFuZ2xlPTkwLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTQwKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT00MCksIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ2luJykpCmBgYAoKVG8gc3RheSBvbiB0aGUgdG9waWMgb2YgZ3JhZGVzLCBhZnRlciByZXNlYXJjaGluZyB0aGUgbGV0dGVyIGdyYWRpbmcgcHJvZ3JhbSwgd2UgZm91bmQgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjogCgorIEJsYW5rIEdyYWRlIChSZWQpOiBUaGUgZm9sbG93aW5nIGFyZSBzY29yZWQgYnV0IG5vdCBncmFkZWQuIEZvciBleC4gSW5pdGlhbCBpbnNwZWN0aW9ucyB0aGF0IHJlc3VsdCBpbiBhIHNjb3JlIG9mIDE0IHBvaW50cyBvciBoaWdoZXIsIG1vbml0b3JpbmcgaW5zcGVjdGlvbnMgYXQgYSByZXN0YXVyYW50IHRoYXQgaGFzIHBlcmZvcm1lZCB2ZXJ5IHBvb3JseSBvbiBpdHMgcmUtaW5zcGVjdGlvbi4gVGhlIEhlYWx0aCBEZXBhcnRtZW50IG1heSBjb250aW51ZSB0byBpbnNwZWN0IHRoZSByZXN0YXVyYW50IHJvdWdobHkgb25jZSBhIG1vbnRoIHVudGlsIGl0IHNjb3JlcyBiZWxvdyAyOCBvciB0aGUgRGVwYXJ0bWVudCBjbG9zZXMgaXQgZm9yIHNlcmlvdXMgYW5kIHBlcnNpc3RlbnQgdmlvbGF0aW9ucywgaW5zcGVjdGlvbnMgYXQgbmV3IHJlc3RhdXJhbnRzIG5vdCB5ZXQgb3BlbiB0byB0aGUgcHVibGljLCBhbiBpbnNwZWN0aW9uIGF0IGEgcmVzdGF1cmFudCBzZWVraW5nIHRvIHJlb3BlbiBhZnRlciB0aGUgRGVwYXJ0bWVudCBjbG9zZWQgaXQsIHNvbWUgaW5zcGVjdGlvbnMgaW4gcmVzcG9uc2UgdG8gY29tcGxhaW50cy4KCisgQSBzY29yZSBvZiBsZXNzIHRoYW4gMTQgcG9pbnRzIG9uIGVpdGhlciBpbml0aWFsIG9yIHJlLWluc3BlY3Rpb24gcmVzdWx0cyBpbiBhbiDigJxB4oCdIGdyYWRlCgorIE9uIHJlLWluc3BlY3Rpb24sIGEgc2NvcmUgb2YgMTQtMjcgcG9pbnRzIG1lYW5zIGEgcmVzdGF1cmFudCByZWNlaXZlcyBib3RoIGEg4oCcQuKAnSBncmFkZSBhbmQgYSDigJxHcmFkZSBQZW5kaW5n4oCdIGNhcmQuCgorIE9uIHJlLWluc3BlY3Rpb24sIGEgc2NvcmUgb2YgMjggb3IgbW9yZSBwb2ludHMgbWVhbnMgYSByZXN0YXVyYW50IHJlY2VpdmVzIGJvdGggYSDigJxD4oCdIGdyYWRlIGFuZCBhIOKAnEdyYWRlIFBlbmRpbmfigJ0gY2FyZC4KCisgQm90aCBaIGFuZCBQIHJlcHJlc2VudCBncmFkZSBwZW5kaW5nLCBob3dldmVyIFAgcmVwcmVzZW50cyBhIEdyYWRlIFBlbmRpbmcgaXNzdWVkIG9uIHJlLW9wZW5pbmcgZm9sbG93aW5nIGFuIGluaXRpYWwgaW5zcGVjdGlvbiB0aGF0IHJlc3VsdGVkIGluIGEgY2xvc3VyZS4KCldlIGFsc28gZGlzY292ZXJlZCB0aGF0IG5vdCBldmVyeSBpbnNwZWN0aW9uIGlzICJncmFkYWJsZSIuIEdyYWRhYmxlIGluc3BlY3Rpb25zIGhhdmUgdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOgoKKyBJTlNQRUNUSU9OIFRZUEUgaW4gKEN5Y2xlIEluc3BlY3Rpb24vSW5pdGlhbCBJbnNwZWN0aW9uLCBDeWNsZSBJbnNwZWN0aW9uL1JlLUluc3BlY3Rpb24sIFByZS1QZXJtaXQgKE9wZXJhdGlvbmFsKS9Jbml0aWFsIEluc3BlY3Rpb24sIFByZS1QZXJtaXQgKE9wZXJhdGlvbmFsKS9SZS1JbnNwZWN0aW9uKQoKKyBBQ1RJT04gaW4gKFZpb2xhdGlvbnMgd2VyZSBjaXRlZCBpbiB0aGUgZm9sbG93aW5nIGFyZWEocyksIE5vIHZpb2xhdGlvbnMgd2VyZSByZWNvcmRlZCBhdCB0aGUgdGltZSBvZiB0aGlzIGluc3BlY3Rpb24sIEVzdGFibGlzaG1lbnQgQ2xvc2VkIGJ5IERPSE1IKQoKKyBJTlNQRUNUSU9OIERBVEUgPiBKdWx5IDI2LCAyMDEwCgpUaGlzIGNhbiBwcm9iYWJseSBleHBsYWluIGEgZmFpciBhbW91bnQgb2YgdGhlIG1pc3NpbmcgZ3JhZGUgZGF0YSBvYnNlcnZlZCBpbiBvdXIgcGxvdC4KCkFjY29yZGluZyB0byB0aGUgQUJPVVQgdGhlIGRhdGEgc2V0IHBhZ2U6IFRoZSBTQ09SRSBhbmQgR1JBREUgZmllbGRzIG1heSBiZSBpbmNvbnNpc3RlbnQgd2l0aCBlYWNoIG90aGVyIGJlY2F1c2Ugb2YgbGltaXRhdGlvbnMgb3IgZXJyb3JzIGluIHRoZSBkYXRhIHN5c3RlbXMuIFRoYXQgaXMgdG8gc2F5LCBzY29yZXMgb2YgMC0xMywgMTQtMjcgYW5kIDI4KyBhcmUgbm90IGFsd2F5cyBhY2NvbXBhbmllZCBieSBBLCBCIGFuZCBDIGdyYWRlcywgcmVzcGVjdGl2ZWx5LCB3aGVuIHRoZXkgc2hvdWxkIGJlLiBUaGVyZSBtYXkgYWxzbyBiZSBjYXNlcyB3aGVyZSBhIGdyYWRlIGNhcmQgd2FzIGdpdmVuIG91dCBidXQgYSByZWNvcmQgb2YgdGhhdCBncmFkZSBpc3N1YW5jZSBpcyBtaXNzaW5nIGZyb20gdGhlIGRhdGEgc3lzdGVtLCBhbmQgdGhlcmVmb3JlIG1pc3NpbmcgZnJvbSB0aGlzIGRhdGFzZXQsIGV2ZW4gdGhvdWdoIHRoZSBTQ09SRSBmaWVsZCBpcyBwb3B1bGF0ZWQuICBOb3RlIHRoYXQgd2hlbiBpbml0aWFsIGluc3BlY3Rpb25zIGFyZSBhZGp1ZGljYXRlZCBkb3duIHRvIHRoZSBBIHJhbmdlLCB0aGUgYWJzZW5jZSBvZiBhbiBhY2NvbXBhbnlpbmcgZ3JhZGUgYXNzb2NpYXRlZCB3aXRoIHRoYXQgaW5zcGVjdGlvbiBpcyBjb3JyZWN0LCBiZWNhdXNlIHRoZSBncmFkZSB3b3VsZCBub3QgYmUgYXNzaWduZWQgdW50aWwgdGhlIHJlLWluc3BlY3Rpb24gaXMgcGVyZm9ybWVkLiAKClRvIGdhaW4gc29tZSBmaW5hbCBpbnNpZ2h0IG9uIHRoZSBkYXRhIHF1YWxpdHksIHdlIGRlY2lkZWQgdG8gcGxvdCB0aGUgcmVsYXRpb25zaHAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIG1pc3Npbmcgc2NvcmVzIGJ5IGdyYWRlIGFuZCBieSB3aGV0aGVyIG9yIG5vdCBhIHZpb2xhdGlvbiB3YXMgcmVwb3J0ZWQuIFdlIHRyYW5zZm9ybWVkIHRoZSBhY3Rpb25zIHRha2VuIGludG8gdGhyZWUgY2F0ZWdvcmllczoKMS4gTm8gdmlvbGF0aW9ucyB3ZXJlIHJlY29yZGVkIGF0IHRoZSB0aW1lIG9mIHRoaXMgaW5zcGVjdGlvbiB0byBObyBWaW9sYXRpb24KMi4gQW55IGFjdGlvbiByZXBvcnRlZCB0byBWaW9sYXRpb24gcmVwb3J0ZWQKMy4gTWlzc2luZyBhY3Rpb25zIHRvIE5BCldlIHRoZW4gY291bnRlZCBpZiB0aGUgc2NvcmUgd2FzIHByb3ZpZGVkIG9yIG5vdC4KCmBgYHtyLGZpZy5oZWlnaHQ9NCwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KHBseXIpCnNjb3JlX2dyYWRlIDwtIFZpb2xhdGlvbnNEYXRhWyAtYygxOjksIDExOjEzLCAxNjoxOCkgXQpzY29yZV9ncmFkZVtzY29yZV9ncmFkZSA9PSAnJ10gPC0gTkEKc2NvcmVfZ3JhZGVfY29tYm9zIDwtIHNjb3JlX2dyYWRlICAlPiUgbXV0YXRlKG1pc3Npbmdfc2NvcmUgPSBpZmVsc2UoaXMubmEoU0NPUkUpLCAieWVzIiwgIm5vIikpCnNjb3JlX2dyYWRlX21pc3NpbmcgPC0gY291bnQoc2NvcmVfZ3JhZGVfY29tYm9zLCBjKCdHUkFERScsICdtaXNzaW5nX3Njb3JlJywgJ0FDVElPTicpKQpzY29yZV9ncmFkZV9taXNzaW5nIDwtIHNjb3JlX2dyYWRlX21pc3NpbmcgJT4lIAogIG11dGF0ZSh2aW9sYXRpb24gPSBpZmVsc2UoQUNUSU9OID09ICdObyB2aW9sYXRpb25zIHdlcmUgcmVjb3JkZWQgYXQgdGhlIHRpbWUgb2YgdGhpcyBpbnNwZWN0aW9uLicsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8gdmlvbGF0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoc2NvcmVfZ3JhZGVfbWlzc2luZyRBQ1RJT04pLCBOQSwgIlZpb2xhdGlvbiBSZXBvcnRlZCIpKSkgJT4lCiAgc2VsZWN0KC1jKEFDVElPTikpCmdncGxvdChzY29yZV9ncmFkZV9taXNzaW5nLCBhZXMoeCA9IEdSQURFLCB5ID0gbG9nKGZyZXEpLCBmaWxsID0gbWlzc2luZ19zY29yZSkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJykgKyBmYWNldF93cmFwKH52aW9sYXRpb24pICsgCiAgZ2d0aXRsZSgiR3JhZGUgYW5kIG1pc3Npbmcgc2NvcmUgY29tYmluYXRpb25zIGJ5IHZpb2xhdGlvbiByZXBvcnQiKSArCiAgbGFicyh4ID0gIkdyYWRlIiwgeSA9ICJMb2coRnJlcXVlbmN5KSIpCmBgYAoKT3RoZXIgaW50ZXJlc3RpbmcgaW5zaWdodHMgYnkgZXhwbG9yaW5nIGRhdGEgbWFudWFsbHkgYXJlOgoKMS4gR3JhZGVzIG9mIE5BIHJlcG9ydGVkIGhpZ2ggZnJlcXVlbmN5IG9mIHNjb3JlIGluIGJvdGggTm8gdmlvbGF0aW9uIGFuZCB2aW9sYXRpb24gcmVwb3J0ZWQgY2F0ZWdvcnkuCgoyLiBBdCBmaXJzdCwgaXQgYXBwZWFycyB0aGF0IGhpZ2ggc2NvcmVzIGFyZSByZWxhdGVkIHRvIGxvdyBncmFkZXMgb3IgbmVlZHMgZ3JhZGluZyBidXQgdGhlbiB3ZSBmaW5kIHJlc3RhdXJhbnRzIHdpdGggYSBncmFkZSBvZiBBIHRoYXQgaGFzIHRoZSBzYW1lIHNjb3JlIGFzIGEgcmVzdGF1cmFudCB3aXRoIGEgZ3JhZGUgb2YgQy4KCjMuIEFub3RoZXIgaW5zaWdodCBieSBqdXN0IGxvb2tpbmcgYXQgdGhlIGRhdGEgaXMgd2Ugc3VycHJpc2luZ2x5IHNhdyB0aGF0IHJlc3RhdXJhbnRzIHdpdGggYSBjcml0aWNhbCBmbGFnIHN0aWxsIHJlY2VpdmUgZ3JhZGVzIG9mIEEuCgojIyBFeGVjdXRpdmUgU3VtbWFyeQpOWUMgcHV0cyBhIGxvdCBvZiB0aW1lIGFuZCBtb25leSBpbnRvIGluc3BlY3RpbmcgcmVzdHVhcmFudHMuIFdoeSB3b3VsZCB0aGV5IGdvIHRocm91Z2ggYWxsIHRoaXMgdHJvdWJsZT8gVG8gZW5zdXJlIHF1YWxpdHkgbWVhbHMgYW5kIHNhdGlzZmFjdGlvbiBvZiBOWUMgcmVzaWRlbnRzIG9mIGNvdXJzZSEgSXQgaXMgaW1wb3J0YW50IGZvciByZXN0YXVyYW50cyBhbmQgZXN0YWJsaXNobWVudCB0aGF0IG1lZXQgYXQgbGVhc3QgdGhlIG1pbmltdW0gcmVxdWlyZW1lbnRzIG9mIGhlYWx0aCBhbmQgc2FmZXR5IHJlZ3VsYXRpb25zIGluIG9yZGVyIHRvIHByb21vdGUgbGVzcyBmb29kIHNpY2sgcmVzaWRlbnRzIGFuZCBhIGNsZWFuZXIgTllDLiAKCkhvdyBjYW4gd2UgdGVsbCBpZiB0aGVzZSBpbnNwZWN0aW9ucyBhcmUgYWN0dWFsbHkgd29ya2luZyB0byBwcm9tb3RlIHJlc3R1YXJhbnRzIHRvIG1lZXQgcmVndWxhdGlvbnM/IExldCdzIHRha2UgYSBsb29rIGF0IHRoZSBwcm9wb3J0aW9uIG9mIHNjb3JlcyB0aGF0IHdlcmUgZ3JhZGVkIGFuIEEgaW4gMjAxMyBhbmQgdGhlIHByb3BvcnRpb24gb2Ygc2NvcmVzIHRoYXQgd2VyZSBncmFkZWQgYW4gQSBpbiAyMDE2LiBMZXQncyB2aWV3IHRoaXMgaW5mb3JtYXRpb24gYnkgbG9jYXRpb24gc28gdGhhdCB5b3Uga25vdyB3aGF0IG5laWdoYm9yaG9vZCB0byBjaG9vc2Ugd2hlbiB5b3UncmUgY3JhdmluZyBhIHJlc3RhdXJhbnQuCgpgYGB7ciBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTMucG5nJykKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTYucG5nJykKYGBgCgpUaGUgZGFya2VyIHRoZSBzaGFkZSBvZiByZWQsIHRoZSBoaWdoZXIgcHJvcG9ydGlvbiBvZiBBIGdyYWRlcy4gSXQgaXMgY2xlYXIgdGhhdCBvdmVyIHRoZSBsYXN0IDMgeWVhcnMsIHRoZSBwcm9wb3J0aW9uIG9mIHJlc3R1YXJhbnRzIHdpdGggYSBncmFkZSBvZiBhbiBBIGhhcyBpbnNjcmVhc2VkLiBOWUMgaW5zcGVjdGlvbnMgbXVzdCBiZSB3b3JraW5nIHRvIGltcHJvdmUgdGhlIHF1YWxpdHkgb2YgdGhlIHJlc3R1YXJhbnRzIHdlIGVhdCBpbiEgSW4gMjAxMywgaXQgc2VlbXMgdGhhdCB0aGUgdGhlcmUgd2VyZSBvbmx5IGEgZmV3IG5laWdoYm9yaG9vZHMgd2l0aCBhbiBleHRyZW1lbHkgaGlnaCBwcm9wb3J0aW9uIG9mIEEgZ3JhZGVzLiBPbmx5IDMgYXJlYXMgaW4gU3RhdGVuIElzbGFuZCwgMSBpbiBMb25nIElzbGFuZCwgYSBmZXcgaW4gQnJvb2tseW4sIE1hbmhhdHRhbiwgYW5kIHRoZSBCcm9ueC4gSW4gMjAxNiBvbiB0aGUgb3RoZXIgaGFuZCwgdGhlIHByb3BvcnRpb24gb2YgQSBncmFkZXMgaXMgdmVyeSBoaWdoIGFsbW9zdCByZWdhcmRsZXNzIG9mIG5laWdoYm9yaG9vZC4gS2VlcCBpdCB1cCBOWUMgcmVzdGFydWFudCBpbnNwZWN0aW9ucyEKClRvIHNlZSB0aGlzIGZyb20gYW5vdGhlciBhbmdsZSwgbGV0J3MgbG9vayBhdCB0aGUgYXZlcmFnZSBzY29yZXMgcGVyIG5laWdoYm9yaG9vZCBpbiAyMDEzIGFuZCAyMDE2LiBBdmVyYWdlIHNjb3JlcyB3ZXJlIGJpbm5lZCBpbiB0ZWggbGVnZW5kIHN1Y2ggdGhhdDoKCisgMSBtZW5hcyB0aGUgYXZlcmFnZSBzY29yZSB3YXMgbGVzcyB0aGFuIDEwLAoKKyAyIGlmIHRoZSBhdmVyYWdlIHNjb3JlIHdhcyBiZXR3ZWVuIDEwIGFuZCAyMCwgCgorIDMgaWYgdGhlIGF2ZXJhZ2Ugc2NvcmUgd2FzIGJldHdlZW4gMjAgYW5kIDMwLAoKKyA0IGlmIHRoZSBhdmVyYWdlIHNjb3JlIHdhcyBiZXR3ZWVuIDMwIGFuZCA0MCwKCisgNSBpZiBpdCB3YXMgYmV0d2VlbiBhIDQwIGFuZCA1MC4KCmBgYHtyIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1Njb3JlMjAxMy5wbmcnKQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1Njb3JlMjAxNi5wbmcnKQpgYGAKCkp1c3QgbG9vayBob3cgbXVjaCBsaWdodGVyIHRoZSBjb2xvciBvZiBlYWNoIG5laWdoYm9yaG9vZCBnb3QhIExpZ2h0ZXIgY29sb3JzIG1lYW4gYSBsb3dlciBhdmVyYWdlIHNjb3JlLCB3aGljaCBjb3JyZWxhdGVzIHRvIGxlc3MgdmlvbGF0aW9ucyBhbmQgYSBoZWFsdGhpZXIgZXN0YWJsaXNobWVudCEKCldlbGwgbm93IHdlIGtub3cgd2hhdCBuZWlnaGJvcmhvb2RzIHRvIGJlIGluIGZvciBlc3RhYmxpc2htZW50cyB3aXRoIGxvdyBzY29yZXMgYW5kIEEgZ3JhZGVzLCBidXQgd2hhdCBhcmUgdGhlIGF2ZXJhZ2Ugc2NvcmVzIGJhc2VkIHVwb24gY3Vpc2luZT8KCmBgYHtyIGVjaG8gPSBGQUxTRX0KbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKYXZlcmFnZV9zY29yZXMgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgLVpJUENPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1QSE9ORSwgLUlOU1BFQ1RJT04uREFURSwgLUFDVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVZJT0xBVElPTi5DT0RFLCAtVklPTEFUSU9OLkRFU0NSSVBUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtQ1JJVElDQUwuRkxBRywgLUdSQURFLCAtR1JBREUuREFURSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVJFQ09SRC5EQVRFLCAtSU5TUEVDVElPTi5UWVBFKQoKYXZlcmFnZV9jdWlzaW5lIDwtIGF2ZXJhZ2Vfc2NvcmVzICU+JSBncm91cF9ieShDVUlTSU5FLkRFU0NSSVBUSU9OKSAlPiUgbmEub21pdCAlPiUKICBkcGx5cjo6c3VtbWFyaXplKGF2ZXJhZ2Vfc2NvcmUgPSBtZWFuKFNDT1JFKSkKYXZlcmFnZV9jdWlzaW5lIDwtIGFycmFuZ2UoYXZlcmFnZV9jdWlzaW5lLCAtYXZlcmFnZV9zY29yZSkKYGBgCgpgYGB7ciBlY2hvPUZBTFNFfQpuIDwtIG5yb3coYXZlcmFnZV9jdWlzaW5lKQpiZXN0MTAgPC0gYXZlcmFnZV9jdWlzaW5lWyhuLSAxMCk6bixdCmJlc3QxMCA8LSBiZXN0MTBbb3JkZXIoYmVzdDEwJGF2ZXJhZ2Vfc2NvcmUpLF0KCmdncGxvdChiZXN0MTAsIGFlcyhyZW9yZGVyKHggPSBDVUlTSU5FLkRFU0NSSVBUSU9OLCAtYXZlcmFnZV9zY29yZSksIGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSBDVUlTSU5FLkRFU0NSSVBUSU9OKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKStnZ3RpdGxlKCJBdmVyYWdlIHNjb3JlIG9mIHRvcCAxMCBjdWlzaW5lcyIpK3hsYWIoIkN1aXNpbmUgZGVzY3JpcHRpb24iKSt5bGFiKCJhdmVyYWdlIHNjb3JlIikrZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMmYiLCBhdmVyYWdlX3Njb3JlKSkscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCNwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LCBzaXplID0gNCkKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CndvcnN0MTAgPC0gYXZlcmFnZV9jdWlzaW5lWzE6MTAsXQoKZ2dwbG90KHdvcnN0MTAsIGFlcyhyZW9yZGVyKHggPSBDVUlTSU5FLkRFU0NSSVBUSU9OLCAtLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLCBmaWxsID0gQ1VJU0lORS5ERVNDUklQVElPTikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBzY29yZSBvZiBXb3JzdCAxMCBjdWlzaW5lcyIpK3hsYWIoIkN1aXNpbmUgZGVzY3JpcHRpb24iKSt5bGFiKCJhdmVyYWdlIHNjb3JlIikrZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMmYiLCBhdmVyYWdlX3Njb3JlKSkscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKQpgYGAKCkl0IGlzIGludGVyZXN0aW5nIHRoYXQgTm90IExpc3RlZC9Ob3QgQXBwbGljYWJsZSBhbmQgT3RoZXIgbWFkZSBpdCB0byB0aGUgdG9wIDEwIGJ1dCB0aGVyZSB5b3UgaGF2ZSBpdCwgdGhlIGJlc3QgYW5kIHdvcnN0IGN1aXNpbmVzIGJhc2VkIHVwb24gdGhlaXIgYXZlcmFnZSBzY29yZXMuCgojIyBNYWluIEFuYWx5c2lzCkFmdGVyIGFuYWx5emluZyB0aGUgcXVhbGl0eSBvZiB0aGUgZGF0YSBzZXQsIHdlIGdvdCByaWQgb2YgZGF0YSBpbiB3aGljaCB0aGUgQm9yb3VnaCBpcyBtaXNzaW5nIGFuZCB0aGUgeWVhciBpcyBiZWZvcmUgMjAxMy4KCmBgYHtyfQpWaW9sYXRpb25zRGF0YSA8LSBWaW9sYXRpb25zRGF0YSAlPiUgZmlsdGVyIChCT1JPICE9ICJNaXNzaW5nIikKVmlvbGF0aW9uc0RhdGEgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIGZpbHRlcigKICBhcy5udW1lcmljKGZvcm1hdChJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkgPiAyMDEyKQpgYGAKCk5vdyB3ZSBjYW4gZ2V0IGEgYmV0dGVyIHBpY3R1cmUgb2YgdGhlIHRvdGFsIG51bWJlciBvZiBpbnNwZWN0aW9ucyBieSB5ZWFyIGFuZCBib3JvdWdoLgpgYGB7cn0KYm9yb3VnaFBsb3QgPC0gZ2dwbG90KFZpb2xhdGlvbnNEYXRhLCBhZXMoQk9STyxmaWxsPUJPUk8pKQpib3JvdWdoUGxvdCArIGdlb21fYmFyKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIAogIGZhY2V0X3dyYXAofmZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQoSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKSkgKyAKICBnZ3RpdGxlKCJUb3RhbCBJbnNwZWN0aW9ucyBmcm9tIDIwMTMtMjAxNyBpbiBlYWNoIEJvcm91Z2giKSArCiAgeGxhYigiQm9yb3VnaCIpICsgeWxhYigiTnVtYmVyIG9mIEluc3BlY3Rpb25zIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYApBZnRlciAyMDEzLCB0aGVyZSBzZWVtcyB0byBiZSBhIGNvbnNpc3RlbnQgYW1vdW50IG9mIGluc3BlY3Rpb25zIGFjcm9zIHRoZSB5ZWFycy4gVGhlIG51bWJlciBvZiBpbnNwZWN0aW9ucyBieSBib3JvdWdoIGFsc28gc2VlbXMgdG8gbWFrZSBzZW5zZSBzaW5jZSB3ZSBleHBlY3QgTWFuaGF0dGFuIHRvIGhhdmUgdGhlIGxhcmdlc3QgbnVtYmVyIG9mIHJlc3R1YXJhbnRzLgoKTmV4dCwgd2UgdG9vayBhIGxvb2sgYXQgdGhlIGdyYWRlIGRpc3RyaWJ1dGlvbiBieSBib3JvdWdoLgpgYGB7cixmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTN9Cmluc3BlY3Rpb25fZ3JhZGVzIDwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIC1aSVBDT0RFLCAtUEhPTkUsIC1BQ1RJT04sIC1WSU9MQVRJT04uQ09ERSwgLVZJT0xBVElPTi5ERVNDUklQVElPTiwgLUNSSVRJQ0FMLkZMQUcsIC1TQ09SRSwgLUdSQURFLkRBVEUsIC1SRUNPUkQuREFURSwgLUlOU1BFQ1RJT04uVFlQRSwtQ1VJU0lORS5ERVNDUklQVElPTikKCmluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcjwtaW5zcGVjdGlvbl9ncmFkZXMgJT4lIHNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQoKaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyIDwtIGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhciAlPiUgZ2F0aGVyKGtleSwgdmFsdWUsIC1CT1JPKSAlPiUgZ3JvdXBfYnkoQk9STywga2V5LCB2YWx1ZSkgJT4lIHRhbGx5ICU+JSBzcHJlYWQodmFsdWUsIG4sIGZpbGwgPSAwKQpuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc193b3llYXIpW25hbWVzKGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcik9PSJrZXkiXSA8LSAiZ3JhZGUiCm5hbWVzKGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcilbbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyKT09IiJdIDwtICJgVW5rbm93biIKaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyIDwtIGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhciAlPiUgZ2F0aGVyKGtleSwgdmFsdWUsIC1CT1JPLC1ncmFkZSkKUmVsRnJlcTwtZnVuY3Rpb24obSl7CiAgICgobSApL3N1bShtKSkKfQoKaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyPC1pbnNwZWN0aW9uX2dyYWRlc193b3llYXIgJT4lIGdyb3VwX2J5KEJPUk8sZ3JhZGUpICU+JQogICAgbXV0YXRlKHBlcmNlbnRhZ2UgPSAodmFsdWUvc3VtKHZhbHVlKSkqMTAwKQpnZ3Bsb3QoaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyLCBhZXMoQk9STywgcGVyY2VudGFnZSAsZmlsbD0ga2V5KSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGdndGl0bGUoJyVHcmFkZSBkaXN0cmlidXRpb24gYWNyb3NzIGJvcm91Z2hzJykgKyAKICBsYWJzKHggPSAiQm9yb3VnaCIsIHkgPSJQZXJjZW50YWdlIikgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkdyYWRlIikpCgpgYGAKV2UgaW5pdGlhbGx5IGh5cG90aGVzaXplZCB0aGF0IHdlIHdvdWxkIHNlZSBhIHBhdHRlcm4gaW4gZ3JhZGUgZGlzdHJpYnV0aW9uIGJ5IGJvcm91Z2gsIGhvd2V2ZXIsIHRoZSBwbG90IHNob3dzIHVzIHRoYXQgZ3JhZGUgZGlzdHJpYnV0aW9ucyBhcmUgYWxtb3N0IHRoZSBzYW1lIHJlZ2FyZGxlc3Mgb2YgYm9yb3VnaC4KCmBgYHtyLGZpZy53aWR0aD04fQoKaW5zcGVjdGlvbl9ncmFkZXNfeWVhcjwtaW5zcGVjdGlvbl9ncmFkZXMlPiUgbXV0YXRlKHllYXI9ZmFjdG9yKGFzLm51bWVyaWMoZm9ybWF0KElOU1BFQ1RJT04uREFURSAsICclWScpKSkpCmluc3BlY3Rpb25fZ3JhZGVzX3llYXI8LWluc3BlY3Rpb25fZ3JhZGVzX3llYXIlPiUgc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpCiBpbnNwZWN0aW9uX2dyYWRlc195ZWFyIDwtIGluc3BlY3Rpb25fZ3JhZGVzX3llYXIgJT4lIGdhdGhlcihrZXksIHZhbHVlLCAtQk9STywteWVhcikgJT4lIGdyb3VwX2J5KEJPUk8seWVhciwga2V5LCB2YWx1ZSkgJT4lIAogICB0YWxseSAlPiUgc3ByZWFkKHZhbHVlLCBuLCBmaWxsID0gMCkjICU+JSBnYXRoZXIoYmxhaCwgLUJPUk8sIC1rZXkpICNzdW1tYXJpemUoYXByb3AgPSBBLyhBK0IrQyspKQpuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc195ZWFyKVtuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc195ZWFyKT09ImtleSJdIDwtICJncmFkZSIKbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfeWVhcilbbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfeWVhcik9PSIiXSA8LSAiYFVua25vd24iCmluc3BlY3Rpb25fZ3JhZGVzX3llYXIgPC0gaW5zcGVjdGlvbl9ncmFkZXNfeWVhciAlPiUgZ2F0aGVyKGtleSwgdmFsdWUsIC1CT1JPLC1ncmFkZSwteWVhcikKUmVsRnJlcTwtZnVuY3Rpb24obSl7CiAgICgobSApL3N1bShtKSkKIH0KaW5zcGVjdGlvbl9ncmFkZXNfeWVhcjwtaW5zcGVjdGlvbl9ncmFkZXNfeWVhciAlPiUgZ3JvdXBfYnkoQk9STyxncmFkZSx5ZWFyKSAlPiUKICAgIG11dGF0ZShwZXJjZW50YWdlID0gKHZhbHVlL3N1bSh2YWx1ZSkpKjEwMCkKZ2dwbG90KGluc3BlY3Rpb25fZ3JhZGVzX3llYXIsIGFlcyhCT1JPLCBwZXJjZW50YWdlICxmaWxsPSBrZXkpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArZmFjZXRfd3JhcCh+eWVhcixucm93PTIsbmNvbD0zKSsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkdyYWRlIikpKwogIGdndGl0bGUoIiVHcmFkZSBkaXN0cmlidXRpb24gYnkgQk9ST1VHSCIpCgpgYGAKCkFkZGluZyB5ZWFyIHRvIHRoaXMgYW5hbHlzaXMgc2hvd2VkIHVzIGFuIGluY3JlYXNlIGluIHRoZSBwcm9wb3J0aWFuIG9mIEFzIGluIFNhdGF0ZW4gSXNsYW5kIGluIDIwMTUgYnV0IHNlZW1lZCBjb25zaXN0ZW50IHRocm91Z2hvdXQgdGhlIHJlc3Qgb2YgdGhlIHBsb3QuCgoKV2UgZGVjaWRlZCB0aGF0IGJvcm91Z2ggbWF5IGJlIHRvbyBnZW5lcmFsIGFuZCB0aHVzIGxvb2tlZCBhdCBncmFkZSBkaXN0cmlidXRpb24gYnkgemlwIGNvZGUgYWNyb3NzIHRoZSB2YXJpb3VzIHllYXJzLiBXZSB1c2VkIGEgaGVhdCBtYXAgdG8gZG8gc28uCmBgYHtyLGZpZy5oZWlnaHQ9MjAsZmlnLndpZHRoPTd9CmxpYnJhcnkodmlyaWRpcykKbm9uWWVhckRhdGFGb3JIZWF0TWFwPC1WaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KEdSQURFLFpJUENPREUpCgpub25ZZWFyRGF0YUZvckhlYXRNYXAgPC0gbm9uWWVhckRhdGFGb3JIZWF0TWFwICU+JSBncm91cF9ieShHUkFERSxaSVBDT0RFKSAlPiUgdGFsbHkgClJlbEZyZXE8LWZ1bmN0aW9uKG0pewogICAoKG0gKS9zdW0obSkpCn0KCm5vblllYXJEYXRhRm9ySGVhdE1hcDwtICBub25ZZWFyRGF0YUZvckhlYXRNYXAgJT4lIGdyb3VwX2J5KFpJUENPREUpJT4lCiAgICBtdXRhdGUocGVyY2VudGFnZSA9IChuL3N1bShuKSkqMTAwKQoKZ2dwbG90KG5vblllYXJEYXRhRm9ySGVhdE1hcCwgYWVzKEdSQURFLCAKICAgICAgICAgICAgICAgICAgICAgICAgWklQQ09ERSwgZmlsbCA9IHBlcmNlbnRhZ2UpKSArCiAgZ2VvbV90aWxlKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBnZ3RpdGxlKCJQZXJjZW50YWdlIGdyYWRlIGRpc3RyaWJ1dGlvbiBieSB6aXBjb2RlXG4gIikreWxhYigiWmlwIENvZGUiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1LCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MTUsYW5nbGU9MCxoanVzdD0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MTAsYW5nbGU9MCxoanVzdD0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwgIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0yNSxhbmdsZT0wLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTMwLGFuZ2xlPTkwLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ2luJykpCmBgYApJdCBpcyBpbnRlcmVzdGluZyB0byBub3RlIHRoYXQgbWlzc2luZyBncmFkZXMgYXJlIHByb2JhYmx5IHRoZSBtb3N0IHByb2JhYmxlIGluIGdlbmVyYWwuIFRoZXJlIGFyZSBzb21lIHppcCBjb2RlcyB3aXRoIGFsbW9zdCBubyBtaXNzaW5nIGdyYWRlcy4gVGhlIHJlc3R1YXJhbnRzIGluIHRob3NlIHNhbWUgemlwIGNvZGVzIHNlZW0gdG8gbW9zdGx5IGhhdmUgYWxsIEEgZ3JhZGVzLiBBbm90aGVyIGludGVyZXN0aW5nIHBvaW50IGlzIDEgemlwIGNvZGUgd2hpY2ggaGFzIGFsbCBOb3QgWWV0IEdyYWRlZCBncmFkZXMuIEluIGdlbmVlcmFsIG1pc3NpbmcgZ3JhZGVlcyBhbmQgZ3JhZGVzIG9mIGFuIEEgc2VlbSB0aGUgbW9zdCBjb21tb24uIFRoaXMgaXMgZm9sbG93ZWQgYnkgZ3JhZGVzIG9mIGEgQi4KClRoZSBuZXh0IHBhcnQgb2Ygb3VyIGFuYWx5c2lzIHdhcyB0byBsb29rIGF0IHRoZSBhdmVyYWdlIHNjb3JlcyBvZiBlYWNoIGN1aXNpbmUuIFdpdGggdGhpcyBpbmZvcm1hdGlvbiwgd2UgY2FuIGhlbHAgY29uc3VtZXJzIHNlZSB3aGF0IGtpbmRzIG9mIGVzdGFibGlzaG1lbnRzIGhhdmUgdGhlIGJlc3QgYW5kIHdvcnN0IHNjb3JlcyBvbiBhdmVyYWdlLiBUaGlzIGluIHRlcm0gY2FuIGhlbHAgYSBjb25zdW1lciBjaG9vc2UgYSB0eXBlIG9mIGN1aXNpbmUgd2hlbiB0aGV5IGFyZSBodW5ncnkuCgpgYGB7cixmaWcuaGVpZ2h0PTIwLGZpZy53aWR0aD01fQphdmVyYWdlX3Njb3JlcyA8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KC1DQU1JUywgLURCQSwgLUJVSUxESU5HLCAtU1RSRUVULCAtWklQQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVBIT05FLCAtSU5TUEVDVElPTi5EQVRFLCAtQUNUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtVklPTEFUSU9OLkNPREUsIC1WSU9MQVRJT04uREVTQ1JJUFRJT04sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1DUklUSUNBTC5GTEFHLCAtR1JBREUsIC1HUkFERS5EQVRFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUkVDT1JELkRBVEUsIC1JTlNQRUNUSU9OLlRZUEUpCgphdmVyYWdlX2N1aXNpbmUgPC0gYXZlcmFnZV9zY29yZXMgJT4lICBncm91cF9ieShDVUlTSU5FLkRFU0NSSVBUSU9OKSAlPiUgbmEub21pdCAlPiUKICBkcGx5cjo6c3VtbWFyaXplKGF2ZXJhZ2Vfc2NvcmUgPSBtZWFuKFNDT1JFKSkKYXZlcmFnZV9jdWlzaW5lIDwtIGFycmFuZ2UoYXZlcmFnZV9jdWlzaW5lLCAtYXZlcmFnZV9zY29yZSkKCmdncGxvdChhdmVyYWdlX2N1aXNpbmUsIGFlcyhyZW9yZGVyKHggPSBDVUlTSU5FLkRFU0NSSVBUSU9OLCAtLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLGZpbGw9IkJsdWUiKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKStnZ3RpdGxlKCJBdmVyYWdlIFNjb3JlcyBBY3Jvc3MgQ3Vpc2luZXMiKSt4bGFiKCJDdWlzaW5lIERlc2NyaXB0aW9uIikreWxhYigiQXZlcmFnZSBTY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksdmp1c3QgPSAwLjUsIHNpemUgPSAzKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1LCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTIwLGFuZ2xlPTAsaGp1c3Q9LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MjAsYW5nbGU9OTAsaGp1c3Q9LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS41LGZhY2U9InBsYWluIikpCmBgYAoKYGBge3J9CndvcnN0MTAgPC0gYXZlcmFnZV9jdWlzaW5lWzE6MTAsXQoKZ2dwbG90KHdvcnN0MTAsIGFlcyhyZW9yZGVyKHggPSBDVUlTSU5FLkRFU0NSSVBUSU9OLCAtLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLCBmaWxsID0gQ1VJU0lORS5ERVNDUklQVElPTikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBzY29yZSBvZiBXb3JzdCAxMCBjdWlzaW5lcyIpK3hsYWIoIkN1aXNpbmUgZGVzY3JpcHRpb24iKSt5bGFiKCJhdmVyYWdlIHNjb3JlIikrZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMmYiLCBhdmVyYWdlX3Njb3JlKSkscG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSkKYGBgCgpgYGB7cn0KbiA8LSBucm93KGF2ZXJhZ2VfY3Vpc2luZSkKYmVzdDEwIDwtIGF2ZXJhZ2VfY3Vpc2luZVsobi0gMTApOm4sXQpiZXN0MTAgPC0gYmVzdDEwW29yZGVyKGJlc3QxMCRhdmVyYWdlX3Njb3JlKSxdCgpnZ3Bsb3QoYmVzdDEwLCBhZXMocmVvcmRlcih4ID0gQ1VJU0lORS5ERVNDUklQVElPTiwgLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLCBmaWxsID0gQ1VJU0lORS5ERVNDUklQVElPTikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBzY29yZSBvZiB0b3AgMTAgY3Vpc2luZXMiKSt4bGFiKCJDdWlzaW5lIGRlc2NyaXB0aW9uIikreWxhYigiYXZlcmFnZSBzY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwjcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSwgc2l6ZSA9IDQpCmBgYAoKSXQgaXMgaW50ZXJlc3RpbmcgdGhhdCB0aGUgbXlzdGVyaW91cyAibm90IGFwcGxpY2FibGUiIiBjdWlzaW5lIGlzIG9uZSBvZiB0aGUgYmVzdCEKCkluIHRoaXMgbmV4dCBwbG90LCB3ZSB3YW50ZWQgdG8gc2VlIGlmIHRoZSBhdmVyYWdlIHNjb3JlIHNpZ25pZmljYW50bHkgZGlmZmVyZWQgYnkgQm9yb3VnaApgYGB7cn0KYXZlcmFnZV9ib3JvdWdoIDwtIGF2ZXJhZ2Vfc2NvcmVzICU+JSAgZ3JvdXBfYnkoQk9STykgJT4lIG5hLm9taXQgJT4lCiAgZHBseXI6OnN1bW1hcml6ZShhdmVyYWdlX3Njb3JlID0gbWVhbihTQ09SRSkpCgpnZ3Bsb3QoYXZlcmFnZV9ib3JvdWdoLCBhZXMocmVvcmRlcih4ID0gQk9STywgLS1hdmVyYWdlX3Njb3JlKSwgYXZlcmFnZV9zY29yZSwgZmlsbCA9IEJPUk8pKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpK2dndGl0bGUoIkF2ZXJhZ2Ugc2NvcmUgYWNyb3NzIGJvcm91Z2hzIikreGxhYigiQm9yb3VnaCIpK3lsYWIoImF2ZXJhZ2Ugc2NvcmUiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGF2ZXJhZ2Vfc2NvcmUpKSxwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpCmBgYAoKQWx0aG91Z2ggd2Ugc2VlIHNsaWdodCBkaWZmZXJlbmNlLCB0aGUgYm9yb3VnaHMgaGF2ZSBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGF2ZXJhZ2Ugc2NvcmUuIFN0YXRlbiBJc2xhbmQgbWF5IGJlIHRoZSBvbmUgZXhjZXB0aW9uLiBXZSBhbHNvIGZhY2V0ZWQgYnkgeWVhciB0byBzZWUgaWYgdGhhdCBtYWRlIGEgZGlmZmVyZW5jZSwgYnV0IHRoZSByZXN1bHRzIHdlcmUgZXNzZW50aWFsbHkgdGhlIHNhbWUgYXMgaW4gdGhlIHBsb3QgYWJvdmUuCgpTbyBmYXIgd2UgbG9va2VkIGF0IGdyYWRlcyBhbmQgc2NvcmVzIGJ1dCBub3QgdGhlIGFjdHVhbCB2aW9sYXRpb25zLiBXaGFyZSBhcmUgdGhlIHRvcCB2aW9sYXRpb25zIHJlc3RhdXJhbnRzIHVzdWFsbHkgZmFjZT8KYGBge3IsZmlnLndpZHRoPTEyfQoKdmlvbGF0aW9uczwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIC1aSVBDT0RFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUEhPTkUsIC1JTlNQRUNUSU9OLkRBVEUsIC1BQ1RJT04sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1WSU9MQVRJT04uQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUNSSVRJQ0FMLkZMQUcsIC1HUkFERSwgLUdSQURFLkRBVEUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1SRUNPUkQuREFURSwgLUlOU1BFQ1RJT04uVFlQRSkKCnZzIDwtIHZpb2xhdGlvbnMgJT4lICBncm91cF9ieShWSU9MQVRJT04uREVTQ1JJUFRJT04pICU+JSBuYS5vbWl0ICU+JQogIGRwbHlyOjpzdW1tYXJpemUoY291bnQgPSBuKCkpCnZzIDwtIGFycmFuZ2UodnMsIC1jb3VudCkKCnRvcHZpb2xhdGlvbnMgPC0gdnNbMToxMCxdCgpsaWJyYXJ5KHN0cmluZ3IpCnRvcHZpb2xhdGlvbnMkdmlvbCA9IHN0cl93cmFwKHRvcHZpb2xhdGlvbnMkVklPTEFUSU9OLkRFU0NSSVBUSU9OLCB3aWR0aCA9IDE1KQoKZ2dwbG90KHRvcHZpb2xhdGlvbnMsIGFlcyhyZW9yZGVyKHZpb2wsIC1jb3VudCksIGNvdW50LGZpbGw9dmlvbCkpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiVG9wIDEwIHZpb2xhdGlvbnMgXG4iKSt4bGFiKCJWaW9sYXRpb24gZGVzY3JpcHRpb24iKSt5bGFiKCJjb3VudCIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjBmIiwgY291bnQpKSwKIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgdmp1c3QgPSAtMC41LCBzaXplID0gNykgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA0MCwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTIwLGFuZ2xlPTAsaGp1c3Q9LjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS41LGZhY2U9InBsYWluIiksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTMwLGFuZ2xlPTAsaGp1c3Q9MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksICAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MzAsYW5nbGU9MCxoanVzdD0uNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9MCxmYWNlPSJwbGFpbiIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0zMCxhbmdsZT05MCxoanVzdD0uNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKYGBgCgpXZSBhbHNvIGh5cG90aGVzaXplZCB0aGF0IHRoZSB0eXBlIG9mIGluc3BlY3Rpb25zIHdvdWxkIGdlbmVyYWxseSB2YXJ5IGJ5IEJvcm91Z2ggYnV0IGV2ZW4gdGhpcyB3YXMgbW9zdGx5IGNvbnNpc3RlbnQuCmBgYHtyLGZpZy5oZWlnaHQ9NiwgbWVzc2FnZSA9IEZBTFNFfQoKIGxpYnJhcnkodmlyaWRpcykKbW9zPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgLVpJUENPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVBIT05FLCAtQUNUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1WSU9MQVRJT04uQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtQ1JJVElDQUwuRkxBRywgLUdSQURFLCAtR1JBREUuREFURSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUkVDT1JELkRBVEUsIC1TQ09SRSwgLUNVSVNJTkUuREVTQ1JJUFRJT04sIC1WSU9MQVRJT04uREVTQ1JJUFRJT04pCm1vcyR5ZWFyIDwtIGZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQobW9zJElOU1BFQ1RJT04uREFURSAsICclWScpKSkKbW9zIDwtIG1vcyAlPiUgc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpCgphdmVyYWdlX21vcyA8LSBtb3MgJT4lIGdyb3VwX2J5KEJPUk8sIHllYXIsIElOU1BFQ1RJT04uVFlQRSkgJT4lIHRhbGx5ICU+JQogZ3JvdXBfYnkoQk9STywgeWVhcikgICU+JSAKIG11dGF0ZShwZXJjZW50YWdlID0gbiAvIHN1bShuKSkKI2F2ZXJhZ2VfY3Vpc2luZSA8LSBhcnJhbmdlKGF2ZXJhZ2VfY3Vpc2luZSwgLWF2ZXJhZ2Vfc2NvcmUpCgpsaWJyYXJ5KHZjZCkKYXZlcmFnZV9tb3MgPC0gYXZlcmFnZV9tb3MgJT4lIHNlbGVjdCgtbikKCgpnZ3Bsb3QoYXZlcmFnZV9tb3MsIGFlcyhCT1JPLCAKICAgICAgICAgICAgICAgICAgICAgICBJTlNQRUNUSU9OLlRZUEUsIGZpbGwgPSBwZXJjZW50YWdlKSkgKwogZ2VvbV90aWxlKCkgKwogc2NhbGVfZmlsbF92aXJpZGlzKCkgKwogI2ZhY2V0X3dyYXAofkJPUk8pCiBnZ3RpdGxlKCJBVkVSQUdFIFZJT0xBVElPTiBTQ09SRSBCWSBaSVAgQ09ERVxuICIpKwogdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzAsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0yMCxhbmdsZT0wLGhqdXN0PS41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0xNSxhbmdsZT0wLGhqdXN0PTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9MCxmYWNlPSJwbGFpbiIpLCAgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTI1LGFuZ2xlPTAsaGp1c3Q9LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MjUsYW5nbGU9OTAsaGp1c3Q9LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS41LGZhY2U9InBsYWluIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MzApLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLCAnaW4nKSkKCmBgYApPbmUgdGhpbmcgd2Ugbm90aWNlZCB3YXMgdGhhdCBTdGF0ZW4gaXNsYW5kIGhhcyB0aGUgbGVhc3QgQ3ljbGUgSW5zcGVjdGlvbi9Jbml0aWFsIEluc3BlY3Rpb24uIE1heWJlIHRoZXkgd2VyZSBvcGVuaW5nIHVwIHRoZSBsZWFzdCBuZXcgcmVzdHVhcmFudHMuIFRoZXkgYWxzbyBoYWQgdGhlIG1vc3QgY3ljbGUgaW5zcGVjdGlvbi9yZS1pbnNwZWN0aW9uIHBlcmNlbnRhZ2UuIEFzIHdlJ2xsIHNlZSBpbiB0aGUgbWFwcyBiZWxvdywgdGhvc2UgcmVpbnNwZWN0aW9ucyBtYXkgaGF2ZSBoZWxwZWQgcmVzdGF1cmFudHMgaW4gc3RhdGVuIGlzbGFuZCBpbXByb3ZlIHRoZWlyIGdyYWRlcyBhbmQgc2NvcmVzLgoKCk9uZSBmYWN0b3Igb2Ygb3VyIGRhdGEgc2V0IHdlIGhhdmVuJ3QgZGlzY3Vzc2VkIHRvbyBtdWNoIGlzIHRoZSBDcml0aWNhbCBmbGFnLCBzYXlpbmcgd2hldGhlciBvciBub3QgYSB2aW9sYXRpb24gaXMgY3JpdGljYWwuIE9uY2UgYWdhaW4sIHdlIGFzc3VtZWQgdGhhdCBvdmVyIHRoZSB5ZWFycyBhbmQgYWNyb3NzIGRpZmZlcmVudCBib3JvdWdocywgdGhlcmUgd291bGQgYmUgc29tZSBwYXR0ZXJuIGluIGNyaXRpY2FsIHZpb2xhdGlvbnMuIEFzIGNhbiBiZSBpbmZlcnJlZCBmcm9tIHRoZSBmb2xsb3dpbmcgcGxvdCwgdGhlcmUgaXMgbm90LgpgYGB7cixmaWcud2lkdGg9NX0KQ3JpdGljYWxpdHlEYXRhPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdChCT1JPLElOU1BFQ1RJT04uREFURSxDUklUSUNBTC5GTEFHKSAlPiUgbmEub21pdCgpCkNyaXRpY2FsaXR5RGF0YSR5ZWFyPC1mYWN0b3IoYXMubnVtZXJpYyggZm9ybWF0KENyaXRpY2FsaXR5RGF0YSRJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkpCiNDcml0aWNhbGl0eURhdGEgPC0gQ3JpdGljYWxpdHlEYXRhICU+JXNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQoKQ3JpdGljYWxpdHlEYXRhIDwtIENyaXRpY2FsaXR5RGF0YSAlPiVzZWxlY3QoLUlOU1BFQ1RJT04uREFURSkgJT4lIGdhdGhlcihrZXksIHZhbHVlLCAtQk9STywgLXllYXIpICU+JSBncm91cF9ieShCT1JPLCB5ZWFyLGtleSx2YWx1ZSkgJT4lIHRhbGx5ICU+JSBzcHJlYWQodmFsdWUsIG4sIGZpbGwgPSAwKQpuYW1lcyhDcml0aWNhbGl0eURhdGEpWzVdIDwtICJOb3RBcHBsaWNhYmxlIgpuYW1lcyhDcml0aWNhbGl0eURhdGEpWzZdIDwtICJOb25Dcml0aWNhbCIKCkNyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2U8LUNyaXRpY2FsaXR5RGF0YSAlPiUgc3VtbWFyaXplKGNyaXRpY2FsUGVyY2VudCA9IENyaXRpY2FsLyhDcml0aWNhbCtOb3RBcHBsaWNhYmxlK05vbkNyaXRpY2FsKSwgTm90QXBwbGljYWJsZVBlcmNlbnQgPSBOb3RBcHBsaWNhYmxlLyhDcml0aWNhbCtOb3RBcHBsaWNhYmxlK05vbkNyaXRpY2FsKSwgTm9uQ3JpdGljYWxQZXJjZW50ID0gTm9uQ3JpdGljYWwvKENyaXRpY2FsK05vdEFwcGxpY2FibGUrTm9uQ3JpdGljYWwpKSMKCm5hbWVzKENyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2UpWzRdIDwtICJDcml0aWNhbCIKbmFtZXMoQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZSlbNV0gPC0gIk5vdEFwcGxpY2FibGUiCm5hbWVzKENyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2UpWzZdIDwtICJOb25Dcml0aWNhbCIKQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZTwtQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZSU+JSBnYXRoZXIoa2V5MSwgdmFsdWUsIC1CT1JPLCAteWVhciwta2V5KQoKCmdncGxvdChDcml0aWNhbGl0eURhdGFQZXJjZW50YWdlLCBhZXMoQk9STywgdmFsdWUsIGZpbGwgPSBrZXkxKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiKSsgeGxhYigiQk9ST1VHSCIpK3lsYWIoIkNSSVRJQ0FMSVRZIFBFUkNFTlRBR0VTIikgK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKyBnZ3RpdGxlKCJHcm91cGVkIGJhcmNoYXJ0IG9mIGdyYWRlIGZyZXF1ZW5jeSBpbiBlYWNoIGN1aXNpbmUgY2F0ZWdvcnkgXG4gd2hlbiB0aGVyZSB3YXMgYSB2aW9sYXRpb24gcmVwb3J0ZWQiKStmYWNldF93cmFwKH55ZWFyLG5yb3c9MixuY29sPTMpK2d1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iQ3JpdGljYWxpdHkgXG4gY2F0ZWdvcnkiKSkKCmBgYApXZSBhdHRlbXB0ZWQgdG8gZnVydGhlciBhbmFseXplIHRoZSBjcml0aWNhbCBmbGFnIGJ1dCB3ZSBsZWFybmVkIHRoYXQgdGhlIGNyaXRpY2FsIGZsYWcgZGlkIG5vdCBoYXZlIHRvbyBtdWNoIGltcGFjdCBvbiBncmFkZSBvciBzY29yZXMuIFRoZXJlIHdhcyBhIGxvdCBvZiBkYXRhIHdpdGggYSBncmFkZSBvZiBBIGJ1dCBhIENyaXRpY2FsIGZsYWcgd2hpbGUgb3RoZXJzIHdpdGggYSB2ZXJ5IGhpZ2ggc2NvcmUgYnkgbm8gY3JpdGljYWwgZmxhZy4KCiMjIFZJU1VBTElTSU5HIERBVEEgV0lUSCBNQVBTCgpGb3IgdGhlIHJlbWFpbmRlciBvZiB0aGUgYW5hbHlzaXMsIHdlIHdpbGwgYmUgd29ya2luZyB3aXRoIFRhYmxlYXUuIFdlIGNob3NlIFRhYmxlYXUgYmVjYXVzZSB3ZSB3YW50ZWQgdG8gcGxvdCBlbGVnZW50IG1hcHMuIFRhYmxlYXUgcHJvdmlkZXMgYSBzaW1wbGVyIGFuZCBtb3JlIGVsZWdlbnQgd2F5IHRvIGRvIHNvIHRoYW4gaW4gUi4KCisgUGxlYXNlIG5vdGUgdGhhdCB0aGVyZSBpcyBhIHR1dG9yaWFsIGZvciBkZXJpdmluZyBtYXBzIGZyb20gZ2VuZXJhdGVkIGRhdHNldCBpbiBUYWJsZWF1IGluIHRoZSBnaXRodWIgcmVwb3NpdG9yeSBhcyBDaG9yb3BsZXRoTWFwcy5odG1sIHVuZGVyIHRoZSAiRmluYWxSZXBvcnQiIGZvbGRlciBpbiB0aGUgR2l0aHViIFJlcG9zaXRvcnkuIEl0IHdhcyBjcmVhdGVkIGJ5IG91ciB2ZXJ5IG93biBMYWtzaHlhIEdhcmcuCgpUaGUgY29kZSBjaHVua3Mgd2lsbCBnZW5lcmF0ZSB0aGUgZGF0YSB0aGF0IHdlIHVwbG9hZCB0byBUYWJsZWF1LiBJbiB0aGUgZm9sbG93aW5nIGFuYWx5c2lzLCB3ZSBleHBsb3JlIHRoZSBwcm9wb3J0aW9uIG9mIEEgZ3JhZGVzIGJhc2VkIG9uIG5laWdoYm9yaG9vZCBvdmVyIHRoZSB5ZWFycy4KYGBge3IsZmlnLmhlaWdodD0xNX0KIyMjIyNHRU5FUkFURSBHUkFERSBQUk9QT0VSVElPTiBEQVRBU0VUIEJZIFlFQVIgRk9SIFRBQkxFQVUgUExPVFRJTkcKemlwZGF0YTwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1QSE9ORSwgLUFDVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVZJT0xBVElPTi5DT0RFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtQ1JJVElDQUwuRkxBRywgLVNDT1JFLCAtR1JBREUuREFURSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVJFQ09SRC5EQVRFLCAtSU5TUEVDVElPTi5UWVBFLCAtVklPTEFUSU9OLkRFU0NSSVBUSU9OLCAtQ1VJU0lORS5ERVNDUklQVElPTiwgLUJPUk8pICU+JSBuYS5vbWl0KCkKemlwZGF0YSR5ZWFyPC1mYWN0b3IoYXMubnVtZXJpYyggZm9ybWF0KHppcGRhdGEkSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKQp6aXBkYXRhR3JhZGVQZXJjZW50YWdlIDwtIHppcGRhdGEgJT4lc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpICU+JWdhdGhlcihrZXksIHZhbHVlLCAtWklQQ09ERSwgLXllYXIpICU+JSBncm91cF9ieShaSVBDT0RFLCB5ZWFyLCBrZXksIHZhbHVlKSAlPiUKICB0YWxseSAlPiUgc3ByZWFkKHZhbHVlLCBuLCBmaWxsID0gMCkgJT4lIHN1bW1hcml6ZShhcHJvcCA9IEEvKEErQitDKSwgYnByb3AgPSBCLyhBK0IrQyksIGNwcm9wID0gQy8oQStCK0MpICkKCiMgZ2dwbG90KHppcGRhdGFHcmFkZVBlcmNlbnRhZ2UsIGFlcyhyZW9yZGVyKHggPSBaSVBDT0RFLCAtLWFwcm9wKSwgYXByb3ApKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyAKIyAgIGNvb3JkX2ZsaXAoKSArIGZhY2V0X3dyYXAofnllYXIpCiMgICB0aGVtZSggYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKSkKYGBgCgojIyMgUFJPUE9SVElPTlMgT0YgR1JBREUgQSBBQ1JPU1MgWUVBUlMKCk92ZXIgdGhlIHllYXJzLCB0aGUgcHJvcG9ydGlvbiBvZiBBJ3MgaGFzIGluY3JlYXNlZCwgYXMgcmVwcmVzZW50ZWQgYnkgdGhlIGRhcmtlciByZWQgc2hhZGluZyBvZiB0aGUgbWFwLiBJdCBpcyB0b28gZWFybHkgdG8gc3R1ZHkgMjAxNyBpbiBkZXB0aCBkdWUgdG8gdGhlIGxpbWl0ZWQgbnVtYmVyIG9mIGluc3BlY3Rpb25zIHNvIGZhci4gTm90ZSB0aGF0IDIwMTcgZGF0YSBtYXBzIGFyZSBvbmx5IGZvciBxdWF0ZXIxIGFuZCBhcmUgbGlrZWx5IHRvIGNoYW5nZS4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXByb3AyMDEzLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTQucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Fwcm9wMjAxNS5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXByb3AyMDE2LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTcucG5nJykKYGBgCgojIyMgUFJPUE9SVElPTlMgT0YgR1JBREUgQiBBQ1JPU1MgWUVBUlMKCkxldCdzIGxvb2sgYXQgaG93IHRoZSBwcm9wb3J0aW9uIG9mIEIncyBjaGFuZ2UuV2UgY2FuIHNlZSB0aGF0IG92ZXIgdGhlIHllYXJzLCB0aGVyZSBzZWVtIHRvIGJlIGxlc3MgQidzIHdoaWNoIG1ha2VzIHNlbnNlIHNpbmNlIG92ZXIgdGhlIHllYXJzIHdlIGhhdmUgbW9yZSBncmFkZXMgb2YgQS4gTm90ZSB0aGF0IDIwMTcgZGF0YSBtYXBzIGFyZSBvbmx5IGZvciBxdWF0ZXIxIGFuZCBhcmUgbGlrZWx5IHRvIGNoYW5nZS4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQnByb3AxLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdCcHJvcDIucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Jwcm9wMy5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQnByb3A0LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdCcHJvcDUucG5nJykKYGBgCgoKIyMjIEFWRVJBR0UgU0NPUkVTIEJZIFpJUENPREUgT1ZFUiBZRUFSUwoKTGV0J3MgbG9vayBhdCB0aGUgYXZlcmFnZSBzY29yZXMgYnkgbmVpZ2hib3Job29kLiBXZSBoYXZlIGFscmVhZHkgZG9uZSBzbyBieSBjdWlzaW5lLgpPdmVyIHRoZSB5ZWFycywgd2UgaGF2ZSBhIGxvd2VyIEF2ZXJhZ2UgU2NvcmUuIFRoZXNlIE5ZQyBpbnNwZWN0aW9ucyBtdXN0IGJlIHByb21wdGluZyByZXN0dXJhbnRzIHRvIGltcHJvdmUgdGhlaXIgZmFjaWxpdGllcyBhbmQgZm9sbG93IHJlZ3VsYXRpb25zIQoKTm90ZSB0aGF0IDIwMTcgZGF0YSBtYXBzIGFyZSBvbmx5IGZvciBxdWF0ZXIxIGFuZCBhcmUgbGlrZWx5IHRvIGNoYW5nZS4KCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1Njb3JlMjAxMy5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnU2NvcmUyMDE0LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdTY29yZTIwMTUucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1Njb3JlMjAxNi5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnU2NvcmUyMDE3LnBuZycpCmBgYAoKIyMjIEFWRVJBR0UgUkUtSU5TUEVDVElPTlMgT1ZFUiBZRUFSUwoKV2UgZGVjaWRlZCB0byBzZWUgd2hpY2ggYXJlYXMgaGFkIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgbnVtYmVyIG9mIHJlaW5zcGVjdGlvbnMuIE1heWJlIHRoaXMgY2FuIGV4cGxhaW4gdGhlIGJldHRlciBzY29yZXMgYW5kIGdyYWRlcyBvdmVyIHRpbWUuSW50ZXJlc3RpbmdseSBlbm91Z2gsIHRoZSBhcmVhcyB3aXRoIHRoZSBtb3N0IHJlaW5zcGVjdGlvbnMgc2VlbSB0byBiZSB0aGUgb25lcyBpbiB3aGljaCB0aGUgZ3JhZGVzIGFuZCBzY29yZXMgaW1wcm92ZWQuIFRoZSBzeXN0ZW0gb2YgcmVpbnNwZWN0aW9ucyBtdXN0IGJlIHdvcmtpbmchCgpOb3RlIHRoYXQgMjAxNyBkYXRhIG1hcHMgYXJlIG9ubHkgZm9yIHF1YXRlcjEgYW5kIGFyZSBsaWtlbHkgdG8gY2hhbmdlLgoKCmBgYHtyfQojIyMgREFUQSBHRU5FUkFUSU9OCmxpYnJhcnkoc3RyaW5ncikKcmVpbnNwZWN0IDwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIC1DVUlTSU5FLkRFU0NSSVBUSU9OLCAtQk9STywgLVNDT1JFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVBIT05FLCBJTlNQRUNUSU9OLkRBVEUsIC1BQ1RJT04sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVZJT0xBVElPTi5DT0RFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1DUklUSUNBTC5GTEFHLCAtR1JBREUsIC1HUkFERS5EQVRFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1SRUNPUkQuREFURSkKcmVpbnNwZWN0JHllYXI8LWZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQocmVpbnNwZWN0JElOU1BFQ1RJT04uREFURSAsICclWScpKSkKCiNpbnNwZWN0aW9uX3R5cGVzIDwtIElOU1BFQ1RJT04uVFlQRQpyZWluc3BlY3QgPC0gcmVpbnNwZWN0ICU+JXNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKSAgJT4lIG5hLm9taXQgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KElOU1BFQ1RJT04uVFlQRSwgIlJlLWluc3BlY3Rpb24iKSklPiVncm91cF9ieShWSU9MQVRJT04uREVTQ1JJUFRJT04sIHllYXIsIFpJUENPREUgKSAgJT4lIHRhbGx5IyBzdW1tYXJpc2UocmUgPSBzdW0oc3RyX2NvdW50KHJlaW5zcGVjdCRJTlNQRUNUSU9OLlRZUEUsICJSZS1pbnNwZWN0aW9uIikpKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnUmVpbnNwZWN0MjAxMy5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnUmVpbnNwZWN0MjAxNC5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnUmVpbnNwZWN0MjAxNS5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnUmVpbnNwZWN0MjAxNi5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnUmVpbnNwZWN0MjAxNy5wbmcnKQpgYGAKCiMjIFNUQVJCVUtTIE9SIERVTktJTiBET05VVFM/Pz8KCkFzIGEgbGFzdCBiaXQgb2YgYW5hbHlzaXMsIHdlIGRlY2lkZWQgdG8gaGVscCBzZXR0bGUgYSBodWdlIGRpbGVtbmEgOiBXaGVyZSBzaG91bGQgeW91IGdldCB5b3VyIGNvZmZlZSwgU3RhcmJ1Y2tzIG9yIER1bmtpbmcgRG9udXRzPwoKYGBge3J9CiMjREFUQSBHRU5FUkFUSU9OIENPREUKbGlicmFyeShzdHJpbmdyKQpDaGFpbnNzRGY8LVZpb2xhdGlvbnNEYXRhJT4lIG11dGF0ZShpc1N0YXJidWNrcz1zdHJfZGV0ZWN0KERCQSwiU1RBUkJVQ0siKSkgJT4lIG11dGF0ZShpc0R1bmtpbj1zdHJfZGV0ZWN0KERCQSwiRFVOS0lOIikpCkNoYWluc3NEZiREQkFbQ2hhaW5zc0RmJGlzU3RhcmJ1Y2tzPT1UUlVFXTwtIlNUQVJCVUNLUyIKQ2hhaW5zc0RmJERCQVtDaGFpbnNzRGYkaXNEdW5raW49PVRSVUVdPC0iRFVOS0lOIgpDaGFpbnNzRGY8LUNoYWluc3NEZiU+JWZpbHRlcihEQkEgJWluJSBjKCJTVEFSQlVDS1MiLCJEVU5LSU4iKSkKQ2hhaW5zc0RmPC1DaGFpbnNzRGYlPiVzZWxlY3QoREJBLEJPUk8sSU5TUEVDVElPTi5EQVRFLFpJUENPREUsU0NPUkUsVklPTEFUSU9OLkRFU0NSSVBUSU9OLEdSQURFKQpDaGFpbnNzRGYkeWVhcjwtZmFjdG9yKGFzLm51bWVyaWMoIGZvcm1hdChDaGFpbnNzRGYkSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKQpDaGFpbnNzRGY8LUNoYWluc3NEZiU+JXNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQpgYGAKCkFzIHlvdSBjYW4gc2VlLCBEdW5raW5nIERvbnV0cyBoYXMgbW9yZSBjcml0aWNhbCB2aW9sYXRpb25zIHRoYW4gU3RhcmJ1Y2tzIGluIGV2ZXJ5IEJvcm91Z2guIE5vdGljaWJsZSBkaWZmZXJlbmNlcyBhcmUgZXNwZWNpYWxseSBzZWUgaW4gQnJvb2tseW4gYW5kIE1hbmhhdHRhbi4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnRFMxLnBuZycpCmBgYAoKCkJvdGggZXN0YWJsaXNobWVudHMgc2hhcmVkIHRoZSBzYW1lIHRvcCB2aW9sYXRpb25zLiBMZXQncyBzZWUgd2hhdCBwZXJjZW50YWdlIG9mIHRoZXNlIHZpb2xhdGlvbnMgZWFjaCBoYXMuIApgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0RTMi5wbmcnKQpgYGAKT25jZSBhZ2FpbiwgU3RhcmJ1Y2tzIGlzIHRoZSB3aW5uZXIhCgpXaGF0IGFib3V0IHRoZSBhdmVyYWdlIHNjb3JlPwpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0RTMy5wbmcnKQpgYGAKClJlZ2FyZGxlcyBvZiB0aGUgeWVhciwgdGhlIGF2ZXJhZ2Ugc2NvcmUgb2YgRHVua2luZyBEb251dHMgaGFzIGJlZW4gaGlnaGVyLiBUaGUgaGlnaGVyIHRoZSBzY29yZSwgdGhlIHdvcnNlLiBOb3RpY2libGUgZGlmZmVyZW5jZXMgYXJlIHNlZW4gaW4gMjAxNSBhbmQgdGhlIGZpcnN0IHRocmVlIG1vbnRocyBvZiAyMDE3LgoKTGV0J3Mgc2VlIGlmIHRoZSBCb3JvdWdoIHlvdXIgaW4gc2hvdWxkIGltcGFjdCB5b3VyIGNob2ljZS4KYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdEUzQucG5nJykKYGBgCgojIyMgV2UgZ3Vlc3Mgd2hlbiB5b3UncmUgaW4gQnJvb2tseW4sIGl0IGRvZXNuJ3QgbWF0dGVyIGJ1dCBldmVyeXdoZXJlIGVsc2UsIHN0aWNrIHRvIFN0YXJidWNrcywgZXNwZWNpYWxseSB5b3UgU3RhdGVuIElzbGFuZCBmb2xrcyEKCiMjIENvbmNsdXNpb24KTWFueSBsaW1pdGF0aW9ucyBpbmNsdWRlZCB0aGUgbWlzc2luZyBkYXRhIGl0c2VsZi4gV2UgbGVhcm5lZCB0aGF0IHNvbWV0aW1lcywgd2hhdCBtYXkgc2VlbSBsaWtlIGFuIGludHVpdGl2ZSBoeXBvdGhlc2lzLCBpcyBhY3R1YWxseSBjb21wbGV0ZWx5IGZhbHNlLiBUaGVyZSB3ZXJlIG5vdCBhcyBtYW55IHBhdHRlcm5zIGFzIHdlIGFudGljaXBhdGVkIGluIHRlcm1zIG9mIEJvcm91Z2guIFRoZSBvbmx5IHRoaW5nIHdlIGRpZCBzZWUgaXMgdGhhdCBvdmVyIHRpbWUsIHRoZSBzY29yZSBhbmQgZ3JhZGUgaGFzIGluY3JlYXNlZCwgc2hvd2luZyB1cyB0aGF0IHRoZSBpbnNwZWN0aW9ucyBhcmUgd29ya2luZyBhbmQgdGhhdCByZXN0dWFyYW50cyBhcmUgaW1wcm92aW5nIHRoZWlyIGZhY2lsaXRpZXMgdG8gcmVjZWlldmUgYSBiZXR0ZXIgc2NvcmUuIEFjY29yZGluZyB0byB0aGUgd2Vic2l0ZSB3ZSByZWNldmVkIHRoZSBkYXRhIGZyb20sIHRocmVlIGZpZWxkcyBhcmUgc29vbiB0byBiZSBhZGRlZCBhcyBkYXRhIGxvZ2ljIGJlY29tZXMgYXZhaWxhYmxlIHRvIHBvcHVsYXRlIHRoZW0gYWNjdXJhdGVseS4gVGhvc2UgZmllbGRzIGFyZSBWSU9MQVRJT04gUE9JTlRTICh0aGUgcG9pbnRzIGFzc2lnbmVkIHRvIGEgdmlvbGF0aW9uIGJlZm9yZSBvciBhZnRlciBhZGp1ZGljYXRpb24sIGRlcGVuZGluZyBvbiB3aGV0aGVyIGFkanVkaWNhdGlvbiBoYXMgb2NjdXJyZWQpLCBGSU5FUyBUT1RBTCAodGhlIGZpbmUgYW1vdW50IGFmdGVyIGFkanVkaWNhdGlvbiksIGFuZCBERUNJU0lPTiBEQVRFIChhZGp1ZGljYXRpb24gZGF0ZSDigJMgb3IgZGF0ZSBhIGdyYWRlIGJlY29tZXMgZmluYWwpLiBXaXRoIHRoaXMgaW5mb3JtYXRpb24sIHdlIGNhbiBkbyBtb3JlIGFuYWx5c2lzIHRvIHNlZSB0aGUgZmluZXMgb2YgdmFyaW91cyB2aW9sYXRpb25zIGFuZCBsZWFybiBob3cgZWFjaCB2aW9sYXRpb24gYWN0dWFsbHkgYWZmZWN0cyB0aGUgc2NvcmUuIFdpdGggdGhhdCwgcmVzdGF1cmFudHMgY2FuIGZvY3VzIG9uIHRoZSBtYWluIHZpb2xhdGlvbnMgdG8gaW1wcm92ZSB0aGVpciBzY29yZXMgaW4gdGhlIG5leHQgaW5zcGVjdGlvbi4KCgoKCgo=